Skip to content

Provider Configuration Guide

Matimo uses a configuration-driven approach to OAuth2 provider endpoints. Instead of hardcoding provider information into the application, all provider definitions are stored in YAML files. This enables:

  • Support for infinite providers without code changes
  • Configuration-driven design - no coupling between code and provider endpoints
  • Easy customization - override endpoints via environment variables or runtime config
  • Zero code modifications - users can add new providers just by creating YAML files

Each OAuth2 provider must have a definition.yaml file in its provider folder:

tools/
├── gmail/
│ └── definition.yaml ← Provider definition
├── github/
│ └── definition.yaml
├── slack/
│ └── definition.yaml
└── [your-provider]/
└── definition.yaml
name: google-provider # Unique name for this provider definition
type: provider # MUST be "provider" to indicate this is an OAuth2 config
version: '1.0.0' # Semantic version of the provider config
description: Google OAuth2 provider # Optional description
provider:
name: google # Provider identifier (used in code)
displayName: Google # Human-readable name
endpoints:
authorizationUrl: https://accounts.google.com/o/oauth2/v2/auth
tokenUrl: https://oauth2.googleapis.com/token
revokeUrl: https://oauth2.googleapis.com/revoke # Optional
defaultScopes: # Optional default scopes
- https://www.googleapis.com/auth/gmail.send
- https://www.googleapis.com/auth/gmail.readonly
documentation: https://developers.google.com/identity/protocols/oauth2

Matimo resolves OAuth2 endpoints using a 3-tier priority system:

1. Runtime Configuration (Highest Priority)

Section titled “1. Runtime Configuration (Highest Priority)”

User provides endpoints directly in code:

const oauth2 = new OAuth2Handler({
provider: 'google',
clientId: '...',
clientSecret: '...',
redirectUri: '...',
endpoints: {
// ← These override everything else
authorizationUrl: 'https://custom.company.com/auth',
tokenUrl: 'https://custom.company.com/token',
},
});

Use case: Custom or internal OAuth2 servers

2. Environment Variables (Medium Priority)

Section titled “2. Environment Variables (Medium Priority)”

Deploy-time configuration via environment variables:

Terminal window
export OAUTH_GOOGLE_AUTH_URL=https://custom.company.com/auth
export OAUTH_GOOGLE_TOKEN_URL=https://custom.company.com/token
export OAUTH_GOOGLE_REVOKE_URL=https://custom.company.com/revoke

Use case: Different endpoints per deployment (dev, staging, prod)

Default endpoints defined in tools/[provider]/definition.yaml:

provider:
endpoints:
authorizationUrl: https://accounts.google.com/o/oauth2/v2/auth
tokenUrl: https://oauth2.googleapis.com/token

Use case: Standard provider defaults

// If config.endpoints is provided → Use that (Priority 1)
const handler = new OAuth2Handler({
provider: 'google',
clientId: '...',
endpoints: { authorizationUrl: 'https://custom/auth', ... } // ← Used
});
// Else if OAUTH_GOOGLE_AUTH_URL env var is set → Use that (Priority 2)
process.env.OAUTH_GOOGLE_AUTH_URL = 'https://custom/auth';
const handler = new OAuth2Handler({
provider: 'google',
clientId: '...',
// No endpoints provided, env var checked
});
// Else use the provider's definition.yaml (Priority 3), needs a loaded loader
const loader = new OAuth2ProviderLoader('./node_modules/@matimo');
await loader.loadProviders();
const handler = new OAuth2Handler({ provider: 'google', clientId: '...', clientSecret: '...', redirectUri: '...' }, loader);

Create typescript/packages/<provider>/definition.yaml (and the Python copy in python/packages/<provider>/src/matimo_<provider>/definition.yaml):

name: microsoft-provider
type: provider
version: '1.0.0'
description: Microsoft Azure AD OAuth2 provider
provider:
name: microsoft
displayName: Microsoft
endpoints:
authorizationUrl: https://login.microsoftonline.com/common/oauth2/v2.0/authorize
tokenUrl: https://login.microsoftonline.com/common/oauth2/v2.0/token
revokeUrl: https://login.microsoftonline.com/common/oauth2/v2.0/token/revoke
defaultScopes:
- https://graph.microsoft.com/Mail.Send
- https://graph.microsoft.com/user.read
documentation: https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-auth-code-flow

Load the provider definitions, then pass the loader to the handler:

import { OAuth2Handler, OAuth2ProviderLoader } from '@matimo/core';
const loader = new OAuth2ProviderLoader('./node_modules/@matimo'); // directory holding the provider packages
await loader.loadProviders();
const oauth2 = new OAuth2Handler(
{
provider: 'microsoft', // provider.name from definition.yaml
clientId: process.env.MICROSOFT_CLIENT_ID!,
clientSecret: process.env.MICROSOFT_CLIENT_SECRET!,
redirectUri: 'http://localhost:3000/callback',
},
loader
);
// Get authorization URL
const authUrl = oauth2.getAuthorizationUrl({
scopes: ['https://graph.microsoft.com/Mail.Send'],
userId: 'user-123',
});

Step 3: (Optional) Override with Environment Variables

Section titled “Step 3: (Optional) Override with Environment Variables”

For deployment-specific endpoints:

Terminal window
export OAUTH_MICROSOFT_AUTH_URL=https://custom-idp.company.com/authorize
export OAUTH_MICROSOFT_TOKEN_URL=https://custom-idp.company.com/token
export OAUTH_MICROSOFT_REVOKE_URL=https://custom-idp.company.com/revoke

File: typescript/packages/gmail/definition.yaml

name: google-provider
type: provider
version: '1.0.0'
provider:
name: google
displayName: Google
endpoints:
authorizationUrl: https://accounts.google.com/o/oauth2/v2/auth
tokenUrl: https://oauth2.googleapis.com/token
revokeUrl: https://oauth2.googleapis.com/revoke
defaultScopes:
- https://www.googleapis.com/auth/gmail.send
- https://www.googleapis.com/auth/gmail.readonly
- https://www.googleapis.com/auth/gmail.compose
documentation: https://developers.google.com/identity/protocols/oauth2

File: typescript/packages/github/definition.yaml

name: github-provider
type: provider
version: '1.0.0'
provider:
name: github
displayName: GitHub
endpoints:
authorizationUrl: https://github.com/login/oauth/authorize
tokenUrl: https://github.com/login/oauth/access_token
defaultScopes:
- user:email
- repo
- gist
documentation: https://docs.github.com/en/developers/apps/building-oauth-apps

File: typescript/packages/slack/definition.yaml

name: slack-provider
type: provider
version: '1.0.0'
provider:
name: slack
displayName: Slack
endpoints:
authorizationUrl: https://slack.com/oauth/v2/authorize
tokenUrl: https://slack.com/api/oauth.v2.access
defaultScopes:
- chat:write
- channels:read
- users:read
documentation: https://api.slack.com/authentication/oauth-v2

Matimo handles OAuth2 flows but does NOT store tokens. Token storage is your responsibility:

import { OAuth2Handler } from '@matimo/core';
// 1. Initialize handler (loader as in "Adding a New Provider")
const oauth2 = new OAuth2Handler(
{
provider: 'google',
clientId: '...',
clientSecret: '...',
redirectUri: 'http://localhost:3000/callback',
},
loader
);
// 2. Generate auth URL
const authUrl = oauth2.getAuthorizationUrl({
scopes: ['https://www.googleapis.com/auth/gmail.send'],
userId: 'user-123',
});
// → Redirect user to authUrl
// 3. Exchange code for token
const token = await oauth2.exchangeCodeForToken(authCode, 'user-123');
// Result: { accessToken, refreshToken, expiresAt, ... }
// 4. YOU store the token (database, Redis, file, etc.)
await database.saveToken('user-123', token);
// 5. Later, retrieve and use the token with Matimo tools
const stored = await oauth2.refreshTokenIfNeeded('user-123', await database.getToken('user-123'));
await matimo.execute(
'gmail-send-email',
{ to: 'recipient@example.com', subject: 'Hi', body: 'Hello' },
{ credentials: { GMAIL_ACCESS_TOKEN: stored.accessToken } } // ← per-call, never shown to the model
);

The provider loader automatically discovers all providers from YAML files:

import { OAuth2ProviderLoader } from '@matimo/core';
const loader = new OAuth2ProviderLoader('./node_modules/@matimo');
const providers = await loader.loadProviders(); // Map<name, endpoints>
// List all discovered providers
loader.listProviders();
// Output: ['github', 'google', 'hubspot', 'microsoft', 'notion', 'slack']
// Get endpoints for specific provider
const googleEndpoints = providers.get('google');
console.log(googleEndpoints);
// Output: {
// authorizationUrl: 'https://accounts.google.com/...',
// tokenUrl: 'https://oauth2.googleapis.com/token',
// revokeUrl: '...'
// }

Use runtime configuration to connect to a custom OAuth2 server:

const oauth2 = new OAuth2Handler({
provider: 'internal-oauth', // Any name
clientId: 'internal-client',
clientSecret: 'internal-secret',
redirectUri: 'http://localhost:3000/callback',
endpoints: {
authorizationUrl: 'https://oauth.company.internal/authorize',
tokenUrl: 'https://oauth.company.internal/token',
revokeUrl: 'https://oauth.company.internal/revoke',
},
});

Or use environment variables:

Terminal window
export OAUTH_INTERNAL_AUTH_URL=https://oauth.company.internal/authorize
export OAUTH_INTERNAL_TOKEN_URL=https://oauth.company.internal/token
export OAUTH_INTERNAL_REVOKE_URL=https://oauth.company.internal/revoke
const oauth2 = new OAuth2Handler({
provider: 'internal',
clientId: '...',
clientSecret: '...',
redirectUri: '...',
// Endpoints loaded from env vars automatically
});

Don’t hardcode endpoints:

const oauth2 = new OAuth2Handler({
provider: 'custom',
clientId: '...',
endpoints: {
authorizationUrl: 'https://hardcoded.example.com/auth', // Bad
},
});

Use YAML or environment variables:

tools/custom/definition.yaml
provider:
endpoints:
authorizationUrl: https://custom.example.com/auth

Include setup instructions in provider definition:

provider:
documentation: https://docs.example.com/oauth2-setup
# Include links to:
# - How to register OAuth app
# - Where to get client ID/secret
# - Required scopes for different use cases

Update version when endpoints change:

version: '1.1.0' # Increment for breaking changes

Always use environment variables:

const oauth2 = new OAuth2Handler({
provider: 'google',
clientId: process.env.GOOGLE_CLIENT_ID, // From env vars
clientSecret: process.env.GOOGLE_CLIENT_SECRET, // From env vars
redirectUri: process.env.GOOGLE_REDIRECT_URI, // From env vars
});

Matimo automatically validates YAML structure:

// This throws MatimoError if definition is invalid
const loader = new OAuth2ProviderLoader('./tools');
await loader.loadProviders();
MatimoError: Unsupported OAuth2 provider: custom. Provide endpoints via:
1. config.endpoints (runtime override)
2. OAUTH_CUSTOM_AUTH_URL env var (deployment config)
3. tools/custom/definition.yaml (YAML configuration)

Solution: Pass endpoints, set both OAUTH_<PROVIDER>_*_URL variables, or create the provider’s definition.yaml and pass a loader on which you called loadProviders(). A handler built without a loader looks in ./tools and never loads it, so only the first two options work there.

MatimoError: Provider validation failed: …

Solution: Ensure YAML has required fields:

  • name
  • type: provider
  • provider.endpoints.authorizationUrl
  • provider.endpoints.tokenUrl

Make sure env var name matches the pattern:

Terminal window
# For provider: 'google'
export OAUTH_GOOGLE_AUTH_URL=...
export OAUTH_GOOGLE_TOKEN_URL=...
export OAUTH_GOOGLE_REVOKE_URL=... # Optional
# For provider: 'microsoft'
export OAUTH_MICROSOFT_AUTH_URL=...