Setting up Okta as an Authentication Server for MCP OAuth Authentication
In this guide, you'll learn how to configure Okta as an authorization server for use with the MCP Server handler. See the MCP Server Handler docs for instructions on how to configure your Zuplo gateway to support OAuth authentication for your MCP Server.
This guide will assume that you already have a working Okta account and organization.
Create an Auth Server
First, you will need to create an Okta authorization server. This server will be used to authorize requests to your MCP Server per the Model Context Protocol authorization specification.
- In the Okta Admin Console, navigate to Security > API in the left sidebar.
- Click Add Authorization Server.
- Set the Name to something like "MCP Server Authorization".
- Set the Audience to the canonical URL of your MCP Server. For example, if
your MCP Server is hosted at
https://my-gateway.zuplo.dev/mcp, then the audience would behttps://my-gateway.zuplo.dev/mcp. The trailing slash is not required. - Add a Description and click Save.
Note the Issuer Metadata URI shown in the authorization server details. You'll need this for your Zuplo configuration.
Configure Scopes
Next, you'll need to configure the scopes for your authorization server.
- In your authorization server settings, click the Scopes tab.
- Click Add Scope.
- Set the Name to something like
mcp:access. - Add a Display phrase and Description (like "Access to MCP Server tools").
- Check Set as a default scope and click Create.
Reserved Okta scopes break MCP clients
Every Okta custom authorization server also publishes device_sso and
interclient_access in its scopes_supported metadata. The Include in public
metadata toggle for those two scopes is disabled, so you can't remove them. An
MCP client that builds its scope list from the authorization server's metadata
requests them together with mcp:access, and Okta rejects the authorization
request with illegal_scope_combination. To keep clients off that list, set
scopesSupported on the OAuthProtectedResourcePlugin in
Configure OAuth on Zuplo below.
Create an OAuth Client Application
Next, you'll need to create an OAuth client application for your MCP server.
Okta requires an admin API key for to dynamically register clients. This may not be well supported by MCP clients. However, MCP clients should also support an alternative way to obtain a client ID and client credential. This document assumes an MCP client can set these fields without having to dynamically register a client.
- In the Okta Admin Console, navigate to Applications > Applications in the left sidebar.
- Click Create App Integration.
- Select OIDC - OpenID Connect as the sign-in method.
- Select Web Application as the application type and click Next.
- Set the App integration name to something like "MCP Client Application".
- For Grant types, check Authorization Code and Refresh Token.
- For Sign-in redirect URIs, leave this empty or set to a placeholder like
http://localhost:3000/callback. - For Controlled access, select Allow everyone in your organization to access.
- Click Save.
After creating the application, note the Client ID and Client Secret from the application's General tab. You'll need these for your MCP client configuration.
Create a Default Policy and Rule
You'll need to create an access policy for your authorization server.
- In your authorization server settings (found in Security > API) click the Access Policies tab.
- Click Add New Access Policy.
- Set the Name to something like "MCP Client Access Policy".
- Add a Description and assign it to All clients.
- Click Create Policy.
Now create a rule for this policy:
- Click Add Rule within your new policy.
- Set the Rule Name to something like "Allow MCP Access".
- In the IF AND section:
- Grant type is: Select the grant type. For the widest grant for all MCP clients, select Client Credentials, Authorization Code, and Device Authorization
- User is: Select Any user assigned the app
- Scopes requested: Select The following scopes and choose the scope
you created for the authorization server (that is,
mcp:access) andoffline_access, so clients can obtain refresh tokens. Okta rejects a request that includes a scope no rule allows, so this list must cover every scope you put inscopesSupportedlater in this guide.
- In the THEN AND section:
- Use this inline hook: None (disabled)
- Access token lifetime is: Set to desired value (for example, 1 hour)
- Refresh token lifetime is: Set to desired value (for example, 90 days)
- Click Create Rule.
Configure OAuth on Zuplo
To set up your gateway to support OAuth authentication for your MCP Server, you will need to do the following:
-
Create an Okta JWT Auth inbound policy on your MCP Server route. This policy will need to have the option
"oAuthResourceMetadataEnabled": trueto enable authorization resource metadata discovery.Code- Replace
my-gateway.zuplo.dev/mcpwith the audience you defined in your authorization server. - Replace
your-okta-domainin theissuerUrlfield with your actual Okta domain. - Replace
your-auth-server-idin theissuerUrlfield with the actual ID of your Okta authorization server.
- Replace
-
Add the OAuth policy to the MCP Server route. For example:
Code -
Add the
OAuthProtectedResourcePluginto yourruntimeInitfunction in themodules/zuplo.runtime.tsfile:Code- Replace
your-okta-domainin theauthorizationServersvalue with your actual Okta domain. - Replace
your-auth-server-idin theauthorizationServersvalue with the actual ID of your Okta authorization server. - Set
scopesSupportedto the scopes you created in Configure Scopes. Keepoffline_accessif clients need refresh tokens. Addopenid,profile, oremailonly if your tokens need those claims.
This plugin populates the
.well-knownroutes for the MCP server auth metadata discovery. This enables MCP clients to automatically discover the authorization issuer endpoint and the scopes to request. See the OAuth Protected Resource Plugin docs for more details on this runtime plugin. - Replace
Testing
The MCP Inspector doesn't currently support setting an initial access token or presenting a UI for setting the client ID or secret.
Refer to the Manual OAuth MCP Testing guide for
further instructions on testing your MCP server with curl.
If you need more help debugging, see Testing OAuth on Zuplo.
Troubleshooting
illegal_scope_combination in the Okta system log
Cause: The MCP client requested device_sso or interclient_access
together with your custom scopes. Okta publishes those two scopes in every
custom authorization server's metadata and can't hide them, and a client that
finds no scopes in the 401 challenge or the protected resource metadata falls
back to that list. Okta rejects the combination and grants no scopes.
Fix: Set scopesSupported on the OAuthProtectedResourcePlugin to the
scopes you created, as shown in
Configure OAuth on Zuplo, and redeploy. The gateway
then advertises exactly those scopes in both the 401 challenge and the metadata
document, so the client never consults the authorization server's list.
Reconnect the client so it repeats discovery.