Configuring Auth0¶
Set up an Auth0 application and API to enable OAuth 2.0 and OpenID Connect (OIDC) authentication for your Actian MCP Server. After you complete these steps, you can see the credentials required for the oauth block in the conf.json configuration file.
For details on shared security concepts like TLS and user impersonation, see Authentication Overview.
Reference
Quick Start¶
The checklist below is the whole procedure in brief. Use it if you are already familiar with the Auth0 Dashboard. Otherwise, work through the numbered steps that follow, which give the full navigation for each item.
- Create an API: Navigate to Applications > APIs > Create API. The Identifier serves as the
FASTMCP_SERVER_AUTH_AUDIENCE. - Create an Application: Navigate to Applications > Applications > Create Application. Select Machine to Machine. Authorize it for the API when prompted. Copy the Client ID and Client Secret.
-
Authorize the Application: In your API's Application Access tab, select
mcp:writeunder both User-Delegated Access and Client Access for your application.Warning
If you skip this step, Auth0 returns an
invalid_requesterror. -
Enable Authorization Code Grant: In Advanced Settings > Grant Types, select Authorization Code.
- Set Callback URLs: Add
<BASE_URL>/auth/callbackto Allowed Callback URLs. - Add the write scope, if
query_modeisread-write: define themcp:writepermission on the API, enable both RBAC Settings toggles, then grant it to users through a role. See Step 1.1 and Step 4.3. - Update Configuration: Add your Auth0 domain and credentials to
conf.json. - Start the server: Launch the server using the
--transport sseorhttp/streamable-httpflag.
Prerequisites¶
- An Auth0 account (sign up free).
- An Auth0 Tenant (created automatically on sign-up, for example,
dev-abc123). Every API, Application, and user you create below lives inside this tenant, and its domain (for example,dev-abc123.us.auth0.com) becomes part of theFASTMCP_SERVER_AUTH_CONFIG_URLyou set inconf.json. - Actian MCP Server installed and ready to run.
Step 1: Create an Auth0 API¶
The API represents the Actian MCP Server as a protected resource in Auth0. Tokens issued by Auth0 include the API's identifier as the audience claim.
- Log in to the Auth0 Dashboard.
- In the left sidebar, navigate to Applications > APIs**.
- Select + Create API.
-
Fill the form as follows:
Field Value Notes Name Actian MCP ServerDisplay name (any descriptive string). Identifier (Audience) https://<mcp-server-host>:8000/mcpLogical identifier (may not be a reachable URL). This becomes your FASTMCP_SERVER_AUTH_AUDIENCE.Signing Algorithm RS256Default, leave the value as is. -
Select Create.
Output of Step 1¶
| Config Field | Where to find it |
|---|---|
FASTMCP_SERVER_AUTH_AUDIENCE |
The Identifier that you entered, for example, https://<mcp-server-host>:8000/mcp. |
Step 1.1: Add the Write Scope (Read-Write Deployments Only)¶
Skip this step if query_mode is read-only. A read-only server never requests the mcp:write scope.
When query_mode is read-write, the server requests mcp:write and rejects any write whose token does not carry it. For more information, see Write support.
- Open your API, for example
Actian MCP Server, and select the Permissions tab. -
Under Add a Permission, enter the following and select + Add:
Field Value Permission mcp:writeDescription Write access -
Select the Settings tab and scroll to RBAC Settings.
-
Enable both of the following:
Setting Why it is required Enable RBAC Auth0 evaluates role and permission assignments during login. Add Permissions in the Access Token Auth0 adds the granted permissions to the access token, where the server reads them. Available only after you enable RBAC. -
Select Save.
Defining the permission does not grant it
At this point mcp:write exists on the API, but no user holds it yet. Assign it to users through a role in Step 4.3.
Step 2: Create an Auth0 Application¶
The Application represents the MCP server's OAuth client. It holds client_id and client_secret used during the OAuth handshake.
Why Machine to Machine?
The MCP server's OAuth proxy (OIDCProxy) acts as a confidential client — it authenticates with Auth0 using a CLIENT_ID and CLIENT_SECRET pair, which is exactly the Machine to Machine pattern. The browser-based user login flow is handled between MCP clients such as Visual Studio Code, Claude Desktop, and similar, and the OIDCProxy itself. MCP clients never talk to Auth0 directly.
Do not use "Regular Web Application"
Auth0 enforces PKCE validation differently for Web applications, which conflicts with the forwarding of OIDCProxy authorization requests. This causes code_challenge: Field required errors.
- In the Auth0 Dashboard, navigate to Applications > Applications.
- Select + Create Application.
-
Enter the values for the following fields:
Field Value Name Actian MCP Server AppApplication Type Machine to Machine Applications -
Select Create.
- When prompted, select your Actian MCP Server API, grant all scopes, and select Authorize (you can also do this later in Step 3).
- The application's Quickstart tab opens.
Configure Application Settings¶
On the Settings tab, configure the following:
| Setting | Value | Notes |
|---|---|---|
| Allowed Callback URLs | https://<mcp-server-host>:8000/auth/callback |
Must exactly match <BASE_URL>/auth/callback. Multiple URLs can be comma-separated. |
| Allowed Logout URLs | https://<mcp-server-host>:8000 |
(Optional) For logout redirect |
| Allowed Web Origins | https://<mcp-server-host>:8000 |
(Optional) For CORS |
Callback URL must match exactly
The Allowed Callback URLs value must match <FASTMCP_SERVER_AUTH_BASE_URL>/auth/callback exactly, including scheme (http or https), host, and port. A mismatch causes Auth0 to reject the login with a redirect_uri_mismatch error.
Select Save Changes.
Configure Grant Types¶
Machine to Machine applications should have Authorization Code enabled by default, but you should always verify since some tenants or configurations may differ.
- On the Settings tab, select Show Advanced Settings.
- Select the Grant Types tab.
- Enable Authorization Code (required for the browser-based OAuth login flow).
- Keep Client Credentials enabled.
- Optionally enable Refresh Token for token refresh support.
- Select Save Changes.
Authorization Code grant is required
Without Authorization Code enabled, Auth0 returns Grant type 'authorization_code' not allowed for the client. This grant type is enabled by default for Machine to Machine applications. If not, re-enable it.
Output of Step 2¶
All values appear on the Settings tab of your application:
| Config Field | Where to find it in Auth0 |
|---|---|
FASTMCP_SERVER_AUTH_CLIENT_ID |
Client ID (at the top of the Settings tab) |
FASTMCP_SERVER_AUTH_CLIENT_SECRET |
Client Secret (click the eye icon to reveal) |
FASTMCP_SERVER_AUTH_CONFIG_URL |
Constructed from Domain: https://<your-domain>/.well-known/openid-configuration |
FASTMCP_SERVER_AUTH_BASE_URL |
MCP server's external URL, for example, https://<mcp-server-host>:8000. |
Finding the Domain
The Domain is shown at the top of the Settings tab, for example, dev-abc123.us.auth0.com. The OIDC discovery URL is always https://<domain>/.well-known/openid-configuration.
Step 3: Authorize the Application for the API¶
This step is critical
Auth0 requires an explicit grant between an application and an API before it issues tokens. Without this authorization, token requests fail with invalid_request.
Authorizing means selecting permissions
Authorizing the application means selecting, from a permission checklist, which of the API's permissions (in this guide, just mcp:write, defined in Step 1.1) the application is allowed to request. If your API defines no permissions yet, the checklist is empty and there is nothing to select — that is expected for read-only deployments.
You can authorize from either the application's APIs tab or the API's Application Access tab:
Option A - Authorize from Application:
- Navigate to Applications > Applications > your app > APIs tab. For example,
Actian MCP Server App. - Select your API from the list. For example,
mcp_serverwith the identifierhttps://<mcp-server-host>:8000/mcp. - On the User-Delegated Access tab, select
mcp:writefrom the permission checklist (or Select: All), then select Save. - Switch to the Client Access tab, select
mcp:writefrom its own permission checklist the same way, then select Save.
Option B - Authorize From API:
- Navigate to Applications > APIs > your API. For example,
mcp_server. - Select the Application Access tab.
- Select your application from the list. For example,
mcp_server (Test Application). - Authorize both User-Delegated Access and Client Access as described in Option A, steps 3-4.
After saving, the application row on the Application Access tab shows a green checkmark and "1 / 1 permissions granted" under both User-Delegated Access and Client Access.
User-Delegated Access is required for user impersonation
If you plan to use user_impersonation: true, the application must be authorized for User-Delegated Access. Without it, Auth0 will not issue tokens with user identity claims (email, sub) during the Authorization Code flow, and the MCP server will not be able to extract a database username.
This is not the same as granting the scope to a user
Authorizing the application here means it is allowed to request mcp:write — not that any particular user's token will carry it. With Enable RBAC on (required in Step 1.1), whether a specific user's token actually includes mcp:write depends on that user holding it through a role, which is a separate, per-user assignment in Step 4.3. Both steps are required for read-write deployments.
Step 4: Create Auth0 Users (If Using User Impersonation)¶
If user_impersonation is true, the authenticated user's identity is forwarded to the database through SET SESSION AUTHORIZATION. Each Auth0 user must have a matching database account. For more information, see User Impersonation.
Step 4.1: Create the User in Auth0¶
- In the Auth0 Dashboard, navigate to User Management > Users.
- Select + Create User.
-
Enter the values for the following fields:
Field Value Notes Email jdoe@example.comValue before @(jdoe) becomes the database usernamePassword A secure password Used for Auth0 login Connection Username-Password-AuthenticationDefault database connection -
Select Create.
Database username = email prefix
The MCP server extracts the database username from the email prefix (the value before @). For example, jdoe@example.com > jdoe. Ensure the email prefix exactly matches the database account name.
Auth0 default behaviour: Auth0's userinfo endpoint does not return a username or preferred_username claim by default. In practice, the server uses the email prefix as the database username. Always create database users to match this email prefix.
Case sensitivity
If the database is case-sensitive, for example, jdoe ≠ Jdoe, ensure the email prefix exactly matches the database account name.
Step 4.2: Create the Matching Database User¶
Auth0 handles authentication, but HCL Informix still needs the user to exist for impersonation to work:
-- Create the user account (DB password not used — Auth0 handles authentication)
CREATE USER mcpuser with password 'mcpuser' properties user 'daemon';;
-- Grant access to the database
GRANT CONNECT TO mcpuser;
-- Grant the necessary table permissions (adjust per your schema)
GRANT SELECT ON TABLE orders TO mcpuser;
GRANT SELECT ON TABLE products TO mcpuser;
-- Set session authorization to the privleged database_user passed to mcp server in conf.json
GRANT SETSESSIONAUTH ON 'mcpuser' TO 'database_user';
Federated identity caveat
If users sign in through Google, Microsoft Entra, SAML, or corporate SSO through Auth0, the sub claim looks like google-oauth2|12345. The server removes the provider prefix, leaving 12345, which is unlikely to match a database account. For SSO setups, set user_impersonation to false unless you can ensure the Auth0 user profile contains a matching username.
Step 4.3: Grant the Write Scope (Read-Write Deployments Only)¶
Skip this step if query_mode is read-only.
Defining mcp:write on the API in Step 1.1 does not give it to anyone. Auth0 issues the scope only to users who hold it through a role, so grant it to each user who is allowed to write.
- In the Auth0 Dashboard, navigate to User Management > Roles.
- Select + Create Role, name it, for example
MCP Writer, and select Create. - On the role's Permissions tab, select Add Permissions.
- Select your API, for example
Actian MCP Server, select themcp:writepermission, and add it. - On the role's Users tab, select Add Users and assign the users who are allowed to write.
Users without this role can still read. Their tokens do not carry mcp:write, so the server rejects their writes. Because the permission is granted per user, a user cannot obtain the scope by asking for it. Keycloak works differently, so if you also run Keycloak, see which users can obtain the scope there.
The database still decides what a user can change
The mcp:write scope permits write statements in general. It does not grant table privileges. With user_impersonation enabled, each write also runs as that user's own database account, so grant the matching INSERT, UPDATE, and DELETE privileges in the database as well. See Step 4.2.
Step 5: Assemble the Final Configuration¶
Mapping Summary¶
conf.json Field |
Auth0 Source | Example Value |
|---|---|---|
FASTMCP_SERVER_AUTH_CONFIG_URL |
https://<Domain>/.well-known/openid-configuration |
https://dev-abc123.us.auth0.com/.well-known/openid-configuration |
FASTMCP_SERVER_AUTH_CLIENT_ID |
Application → Settings → Client ID | wNXUdrp9aBcDeFgHiJkLmN |
FASTMCP_SERVER_AUTH_CLIENT_SECRET |
Application → Settings → Client Secret | a1B2c3D4e5F6g7H8i9J0... |
FASTMCP_SERVER_AUTH_BASE_URL |
Your MCP server's external URL | https://<mcp-server-host>:8000 |
FASTMCP_SERVER_AUTH_AUDIENCE |
API → Identifier | https://<mcp-server-host>:8000/mcp |
user_impersonation |
Your choice | true or false |
Audience fallback
If FASTMCP_SERVER_AUTH_AUDIENCE is omitted, the server uses FASTMCP_SERVER_AUTH_CLIENT_ID as the audience. This is common for Keycloak setups, but for Auth0 you should always set an explicit audience, the Client ID will not match the API Identifier.
Note
The AUDIENCE is a logical identifier used for token validation. It may not need be a reachable HTTPS URL.
Example conf.json¶
{
"driver": "{Ingres}",
"server": "@<db-host>,tcp_ip,<port>",
"database": "mydb",
"database_user": "<database_user>",
"database_password": "<database_password>",
"max_connections": 10,
"host": "0.0.0.0",
"port": 8000,
"query_mode": "read-write",
"write_confirmation": true,
"ssl_certfile": "/app/server.crt",
"ssl_keyfile": "/app/server.key",
"oauth": {
"FASTMCP_SERVER_AUTH_CONFIG_URL": "https://<your-auth0-domain>/.well-known/openid-configuration",
"FASTMCP_SERVER_AUTH_CLIENT_ID": "<your-client-id>",
"FASTMCP_SERVER_AUTH_CLIENT_SECRET": "<your-client-secret>",
"FASTMCP_SERVER_AUTH_BASE_URL": "https://<your-server-host>:8000",
"FASTMCP_SERVER_AUTH_AUDIENCE": "<your-api-identifier>",
"user_impersonation": true
}
}
Note
Replace <db-host> with the database server address. In a Docker container, use the host's IP address or host.docker.internal(not localhost or 127.0.0.1, which refer to the container itself).
For TLS setup details (certificate generation, Docker deployment, trusting self-signed certs), see HTTPS / TLS for Remote Deployments.
For security best practices (file permissions, .gitignore, secrets management), see Security Best Practices.
Verify End-to-End¶
After starting the MCP server container with OAuth configured:
- Open a browser and navigate to your server's
/mcpendpoint, for example,https://<your-server-host>:8000/mcp. - You should be redirected to the Auth0 login page.
- Log in with an Auth0 user, for example, the user you created in Step 4.
- After logging in, Auth0 redirects you back to the MCP server with a valid token.
- Check the server logs for
Stored database username: <username>to confirm user impersonation is active.
Troubleshooting¶
Verify OIDC Discovery Endpoint¶
curl https://dev-abc123.us.auth0.com/.well-known/openid-configuration \
| python3 -m json.tool
You should see issuer, authorization_endpoint, token_endpoint, jwks_uri, and similar.
Common Errors¶
| Error | Cause | Fix |
|---|---|---|
code_challenge: Field required |
Auth0 Application type is "Regular Web Application". | Recreate as Machine to Machine application. Auth0 does not allow changing app type after creation. See Step 2. |
Grant type 'authorization_code' not allowed |
Machine to Machine application is missing Authorization Code grant. | Enable Authorization Code in Advanced Settings > Grant Types. See Configure Grant Types. |
invalid_request when requesting a token |
Application not authorized for the API. | Step 3 - authorize the application. |
audience mismatch |
FASTMCP_SERVER_AUTH_AUDIENCE does not match the API Identifier. |
Ensure they are identical strings. |
invalid_client |
Wrong client_id or client_secret. |
Re-copy from Application > Settings. |
KeyError on startup (for example, CLIENT_SECRET). |
Some OAuth fields are present but others missing. | Provide all required fields or remove oauth entirely. |
Could not extract username |
Token lacks username, preferred_username, or email. |
Add email/profile scopes or set user_impersonation: false. |
unauthorized / 401 on every request |
OAuth misconfigured or token expired. | Check server logs and verify OIDC discovery URL is reachable. |
redirect_uri_mismatch |
Callback URL does not match <BASE_URL>/auth/callback. |
Fix Allowed Callback URLs in Auth0 - scheme, host, and port must match exactly. |
ValueError: Issuer URL must be HTTPS |
OAuth without TLS configured. | Add ssl_certfile/ssl_keyfile and use https:// for BASE_URL. |
ValueError: BASE_URL must start with https:// |
SSL configured but BASE_URL still uses http://. |
Update BASE_URL to https://. |
ssl.SSLError: PEM lib |
Missing cert/key env vars before Docker start. | Mount cert/key as volumes when starting the container (see Docker Deployment). |
ERR_TLS_CERT_ALTNAME_INVALID |
Certificate missing SAN. | Regenerate with -addext "subjectAltName=IP:<ip>". |
TypeError: fetch failed (VS Code) |
Self-signed cert not trusted by Node.js. |
Launch Visual Studio Code with NODE_EXTRA_CA_CERTS=/path/to/server.crt code . |
Client Not Registered (VS Code) |
Server's Docker container was recreated, wiping client registrations, but Visual Studio Code caches the old client ID. | Quit Visual Studio Code, then delete stale registrations from the state DB (see Clearing Visual Studio Code OAuth cache below) and reopen Visual Studio Code. To prevent recurrence, mount a Docker volume for /root/.local/share/fastmcp. |
Service not found: https://... / access_denied |
AUDIENCE mismatch between client request and server config (often http versus https). |
Ensure FASTMCP_SERVER_AUTH_AUDIENCE in conf.json exactly matches the Auth0 API Identifier. |
| Token validation behaves unexpectedly | OIDC endpoint is unreachable at startup. | Restart server after endpoint is accessible. |
Clearing Visual Studio Code OAuth Cache¶
If the MCP server's Docker container is recreated, Visual Studio Code's cached OAuth client registration becomes stale. To clear it:
- Quit Visual Studio Code completely (Cmd+Q on macOS, or close all windows on Linux/Windows).
-
Run the appropriate command for your OS:
sqlite3 ~/Library/"Application Support"/Code/User/globalStorage/state.vscdb \ "DELETE FROM ItemTable WHERE key LIKE '%dynamicAuth%<your-server-host>%';"sqlite3 ~/.config/Code/User/globalStorage/state.vscdb \ "DELETE FROM ItemTable WHERE key LIKE '%dynamicAuth%<your-server-host>%';"sqlite3 "$env:APPDATA\Code\User\globalStorage\state.vscdb" ` "DELETE FROM ItemTable WHERE key LIKE '%dynamicAuth%<your-server-host>%';" -
Reopen Visual Studio Code. It will re-register with the server automatically.
Replace <your-server-host> with your server's IP or hostname, for example, 35.185.60.76. This only clears the registration for that specific server.
Prevent recurrence
Mount a Docker volume for the server's OAuth state, so client registrations survive container recreation:
docker run ... -v mcp-auth-data:/root/.local/share/fastmcp ...
Token Expiration¶
Auth0 tokens have a configurable lifetime:
- Navigate to Applications > APIs > your API > Settings.
- Check Token Expiration (Seconds). Default is 86400 (24 hours).
- Adjust as needed.
Note
Token refresh is handled automatically by the OAuth flow when using browser-based authentication.
Staging Versus Production¶
| Environment | Recommendation |
|---|---|
| Development | Use a free Auth0 tenant. |
| Staging / Production | Use a dedicated Auth0 tenant or separate Application and API. Always use HTTPS for BASE_URL and callback URLs. |