OAuth is the recommended way for the CloudBees CI MCP Router to authenticate to CloudBees CI. Rather than relying on one shared token, each request carries the identity of the person or tool that made it, and the CloudBees CI MCP Router holds only short-lived tokens scoped to the controllers it needs to reach. OAuth uses the following components:
-
An MCP client (such as Claude Code or GitHub Copilot) signs in once and sends an OAuth token to the CloudBees CI MCP Router.
-
The CloudBees CI MCP Router exchanges that token for a short-lived token scoped to the controller it needs to reach, then forwards the request.
-
The controller validates the token and runs the request as the signed-in user.
|
Authenticating with an API token will be deprecated in the future. For new deployments, CloudBees recommends that you use OAuth, which authenticates each request individually rather than relying on a shared token. |
Review the Prerequisites and Pre-seeded OAuth clients, and then choose one of the following methods to enable OAuth:
Prerequisites
Before you begin, ensure that you have the following:
-
The CloudBees OAuth Resource Server plugin (
cloudbees-oauth-resource), installed on the operations center and on every controller that should accept OAuth, and each instance restarted after installation.If your controllers are connected to the operations center, you do not need to configure each controller manually. When a controller connects to the operations center, it is automatically configured with the authorization server to trust. -
The CloudBees OAuth Authorization Server plugin (
cloudbees-oauth-server), installed on the operations center and the instance restarted after installation. -
The CloudBees CI MCP Router installed and running.
Pre-seeded OAuth clients
The authorization server ships with two pre-seeded OAuth clients, so no client registration is required to connect an MCP agent:
-
cloudbees-mcp-router: A confidential client, using the token-exchange grant, that the CloudBees CI MCP Router uses to exchange a user token for a controller-scoped token. -
ci-mcp-client: A public client, using Proof Key for Code Exchange (PKCE), that MCP agents such as Claude Code use to sign in. Select it with the--client-id ci-mcp-clientflag when you connect an agent.
Because these two clients are pre-seeded, an MCP agent using ci-mcp-client connects without needing to register first.
On first use, you are asked to approve the client’s access, unless an administrator has enabled Auto-approve seeded clients on the authorization server.
|
Dynamic client registration (DCR) is disabled by default.
Requests to the Re-enable it only for environments that need self-service registration, such as test clusters or the MCP Inspector. Any client you create manually still prompts for consent on first use. |
Enable OAuth with Helm
If you already deploy CloudBees CI with the cloudbees-core Helm chart, you can deploy the CloudBees CI MCP Router and enable OAuth together by adding the following values.
|
Before proceeding, ensure you have the following:
The following steps cover the settings sufficient for most deployments. For additional tuning options, refer to (Optional) Tune the Helm configuration. |
-
Add the following to your Helm values:
OperationsCenter: OAuthServer: Enabled: true(1) McpRouter: enabled: true(2) upstreamMode: AUTO(3)1 Turns on the authorization server and its discovery endpoints. 2 Deploys the CloudBees CI MCP Router as part of the chart. Omit if you already manually deployed the CloudBees CI MCP Router. 3 AUTOaccepts both OAuth bearer tokens and existingAuthorizationheaders (such as Basic or API token), which is the recommended choice when you migrate to OAuth. Update toOAUTH_ONLYafter every controller has the CloudBees OAuth Resource Server plugin installed and configured. -
Apply the values:
1 Omit if you already manually deployed the CloudBees CI MCP Router. The chart automatically:
-
Configures the authorization server with the addresses allowed to receive tokens (the CloudBees CI MCP Router and the controllers).
-
Configures the operations center and controllers with the authorization server to trust.
-
Exposes the OAuth discovery endpoints so that MCP clients can locate them.
-
Runs the CloudBees CI MCP Router under a dedicated Kubernetes service account and grants it a projected token (audience
cjoc) that the authorization server validates to authenticate token-exchange requests; no shared secret is required.
-
(Optional) Tune the Helm configuration
The values described in Enable OAuth with Helm are sufficient for most deployments. The following values let you tune the authorization server and the CloudBees CI MCP Router when the defaults do not suit your environment.
Tune authorization server values
| Value | Description |
|---|---|
|
Renders the OAuth discovery endpoints and configuration that seeds the CloudBees OAuth Authorization Server and CloudBees OAuth Resource Server plugins on every operations center start.
Grants the CloudBees CI MCP Router a projected service account token to authenticate to the authorization server.
Set to |
|
Public address of the CloudBees CI MCP Router that the authorization server expects in the |
Tune CloudBees CI MCP Router deployment values
| Value | Description | ||
|---|---|---|---|
|
The chart renders a Deployment, Service, and Ingress wired to the operations center.
Set to |
||
|
Authentication mode forwarded to controllers.
|
||
|
By default, the CloudBees CI MCP Router authenticates to the authorization server with its projected service account token.
To use an RFC 7523
When |
||
|
Number of CloudBees CI MCP Router replicas.
The CloudBees CI MCP Router keeps only in-memory caches, so one replica is enough for most fleets. |
||
|
CloudBees CI MCP Router image coordinates.
Override any of these to pull from a private registry or to pin a specific version.
Set |
||
|
Image pull policy for the CloudBees CI MCP Router container. |
||
|
CPU, memory requests, and limits for the CloudBees CI MCP Router container.
Requests and limits are set to the same value so the pod runs in the Kubernetes Guaranteed QoS class. |
||
|
Extra environment variables for the CloudBees CI MCP Router container, for example to set |
||
|
Image pull secrets for a private registry. |
||
|
Standard Kubernetes scheduling, annotation, and security context settings for the CloudBees CI MCP Router pod and container. |
Manually configure OAuth
If you do not use the Helm chart, you must configure the OAuth components manually. Configure the authorization server and resource server in CloudBees CI, and then start the CloudBees CI MCP Router with the corresponding environment variables.
To manually configure OAuth:
-
Configure the authorization server and resource server using one of the following methods:
Configure the authorization server and resource server using the UI
To configure the authorization server and resource server in the CloudBees CI UI:
|
The following steps cover the settings sufficient for most deployments. For additional tuning options, refer to (Optional) Tune the manual configuration. |
Configure the resource server (operations center and controllers)
To configure the resource server on the operations center and on every controller that should accept OAuth:
-
In the operations center and on each controller, navigate to and scroll down to CloudBees OAuth Resource Server.
-
Set Trusted issuer to the issuer URL of the authorization server.
This value must match the Issuer URL of the authorization server exactly. If you use the default authorization server URL, enter
<your-oc-url>/oauth-server. If left blank, OAuth enforcement is disabled and all requests pass through to Jenkins. -
If the canonical address of this instance differs from its root URL, set Accepted audience to the canonical address. Otherwise, leave it blank to use the root URL.
-
Set Filter mode to one of the following:
-
AUTO (recommended): Accepts both OAuth bearer tokens and existing sign-ins; non-Bearer requests are handled by Jenkins directly.
-
OAUTH_ONLY: Accepts the same bearer tokens as AUTO, but challenges non-Bearer requests to protected paths with
401 + PRM. -
ROUTER_ONLY: Accepts only tokens issued through the CloudBees CI MCP Router and rejects all other requests to protected paths.
-
-
Select Save to apply the changes.
Configure the authorization server (operations center only)
To configure the authorization server on the operations center:
-
In the operations center, navigate to and scroll down to CloudBees OAuth Authorization Server.
-
Leave Issuer URL blank to use the default,
<your-oc-url>/oauth-server, which matches the Trusted issuer value set on the resource server. If the authorization server is reachable at a different public address than the operations center, set Issuer URL to that address instead. -
Leave Internal JWKS URL blank in most cases; controllers fetch the signing keys from the issuer’s public
/jwksendpoint. Set it only if a controller cannot reach that public address, for example an internal address reachable only over HTTP. For more information, refer to Resolve OAuth configuration issues. -
For Allowed audiences, add the addresses of the controllers and the CloudBees CI MCP Router that are allowed to receive exchanged tokens, one per line.
-
Set Router client secret to a strong random secret. Record it, as you will need it when you configure the CloudBees CI MCP Router, where it is set as
ROUTER_CLIENT_SECRET. -
Select Save to apply the changes.
(Optional) Tune the manual configuration
The settings above are sufficient for most deployments. The following settings let you tune the resource server and authorization server when the defaults do not fit your environment.
Tune resource server settings (operations center and controllers)
-
In the operations center and on each controller, navigate to and scroll down to CloudBees OAuth Resource Server.
-
Leave JWKS URL override blank in most cases; by default the JWKS is fetched from
{trustedIssuer}/jwksover HTTPS. Set it only if this instance’s public hostname is unreachable from inside the cluster (hairpin NAT), to an internal address such ashttp://cjoc/cjoc/oauth-server/jwks. -
If you selected ROUTER_ONLY for Filter mode, set PRM resource URI to the CloudBees CI MCP Router URL, so MCP clients discover CloudBees CI MCP Router instead of connecting to Jenkins directly.
-
If MCP endpoints on this instance are served from a path other than
/mcp-server/*, add those paths to Protected paths, one per line or comma-separated. -
If you need to tune how long JWKS keys are cached, adjust JWKS cache TTL (default: 300 seconds).
-
If you need to adjust the leeway for token expiry validation, adjust Clock skew (default: 60 seconds).
Tune authorization server settings (operations center only)
-
In the operations center, navigate to and scroll down to CloudBees OAuth Authorization Server.
-
If you want the operations center to overwrite any locally set trusted issuer on connected controllers, select Enforce trusted issuer on controllers. Otherwise, the operations center seeds its issuer only on controllers that have none, leaving deliberate local values alone.
-
If your security policy requires shorter token lifetimes than the defaults, adjust Access token TTL (default: 600 seconds) and Exchanged token TTL (default: 300 seconds). Exchanged tokens should be shorter than access tokens, because they can always be re-exchanged.
-
To let untrusted clients self-register (for example, MCP Inspector or similar tooling that automatically registers), select Enable Dynamic Client Registration. For more information, refer to Pre-seeded OAuth clients.
Leave this disabled on a publicly reachable authorization server to prevent unbounded client creation. -
If you selected Enable Dynamic Client Registration and an MCP client fails to register because it looks for
/registerat the Jenkins root instead of at/oauth-server/register, enable Also serve /register at Jenkins root. -
If you selected Enable Dynamic Client Registration and your security policy requires different DCR client lifetimes than the defaults, adjust DCR client secret TTL (default: 180 days), DCR refresh-token TTL (default: 30 days), and Idle DCR client TTL (default: 90 days).
These lifetimes are entered in seconds in the UI. -
If you selected Enable Dynamic Client Registration and want to manage clients manually through the UI, disable Evict idle DCR clients. Otherwise, leave it enabled so the daily sweep evicts idle DCR clients.
-
To bypass the consent prompt on first use for the pre-seeded
cloudbees-mcp-routerandci-mcp-clientclients, enable Auto-approve seeded clients.Enable this only if you accept that these platform clients act on a user’s identity without explicit approval. -
If clients authenticate with
private_key_jwtand your security policy requires different client assertion or JWKS lifetimes than the defaults, adjust Client assertion max lifetime (default: 300 seconds), Client assertion clock skew (default: 30 seconds), and JWKS cache TTL (default: 300 seconds).This JWKS cache TTL is separate from the resource server setting of the same name. Here it controls how long the authorization server caches the public keys it fetches to verify client assertions.
-
If you use the RFC 7523 jwt-bearer grant to trade external JWTs (such as Kubernetes service account tokens or GitHub Actions OIDC tokens) for CloudBees CI MCP Router tokens, under Trusted assertion issuers, select + Add trusted issuer, and then configure the following for each external issuer:
-
Set Issuer (iss) to the exact value of the assertion’s
issclaim, for example,https://token.actions.githubusercontent.comor the Kubernetes API server issuer. -
Set Expected audience (aud) to a value unique to this authorization server, so a token minted for another service cannot be replayed at this endpoint.
-
Set Bound Jenkins user id to the Jenkins user that every assertion from this issuer maps to. The external token never chooses its own identity; you pin it here.
-
Provide the issuer’s public keys as either Inline JWKS or a JWKS URL. Prefer JWKS URL when the issuer rotates keys.
-
Optionally, in Allowed audiences, add the audiences this issuer’s tokens may target, one per line. Leave blank to inherit the global Allowed audiences list.
-
Optionally, in Allowed subjects, add the external
subvalues to accept from this issuer, one per line. Leave blank to accept any subject the issuer vouches for.For a shared issuer such as GitHub Actions, set Allowed subjects so that only specific external identities can become the bound user, rather than anyone who can mint a token for the expected audience.
-
Configure the authorization server and resource server using Configuration as Code
To configure using Configuration as Code (CasC):
-
In the operations center CasC bundle, add the following to your
jenkins.yamlfile:security: oauthAuthorizationServer: issuer: "https://oc.example.com/oauth-server"(1) routerClientSecret: "<your-shared-secret>"(2) allowedAudiences: |(3) https://controller-a.example.com https://mcp-router.example.com internalJwksUrl: "<internal-address>"(4)1 Public address of the authorization server. 2 Shared secret the CloudBees CI MCP Router uses to authenticate to the authorization server. Use the same value as ROUTER_CLIENT_SECRET(refer to Configure the CloudBees CI MCP Router).3 Addresses of the controllers and the CloudBees CI MCP Router that are allowed to receive exchanged tokens, with one address per line. 4 Optional; usually leave it unset so controllers derive the issuer’s public HTTPS /jwksendpoint. Set it only if a controller cannot reach that public address, for example an internal address reachable only over HTTP. For more information, refer to Resolve OAuth configuration issues. -
In the CasC bundle for the operations center and each controller, add the following to your
jenkins.yamlfile:security: oauthResourceServer: trustedIssuer: "https://oc.example.com/oauth-server"(1) acceptedAudience: "https://controller-a.example.com"(2) filterMode: "AUTO"(3)1 Trusted issuer URL of the authorization server. It must match issuerexactly. OAuth remains disabled until this is set.2 Canonical address of this instance. Defaults to the instance root URL. 3 AUTOaccepts both OAuth and existing sign-ins.OAUTH_ONLYaccepts the same bearer tokens asAUTO, but challenges non-Bearer requests to protected paths with401 + PRM.ROUTER_ONLYaccepts only tokens issued through the CloudBees CI MCP Router. -
Apply the bundle to your operations center and controllers. For more information, refer to Update a CasC bundle.
Configure the CloudBees CI MCP Router
Start the CloudBees CI MCP Router with the following environment variables:
The following values must match the authorization server configuration:
-
OAUTH_ISSUERmust match the Issuer URL. -
ROUTER_CLIENT_SECRETmust match the Router client secret. -
OAUTH_ROUTER_AUDIENCEis the public address of the CloudBees CI MCP Router, and must appear in the Allowed audiences list of the authorization server.
| The router client secret allows the CloudBees CI MCP Router to obtain tokens, so protect it as you would a password. Use a Kubernetes Secret or a secret store rather than passing it on the command line, where it can be exposed in shell history or process listings. |
Verify OAuth is working
-
Verify that the authorization server is published. The following command returns a JSON document that describes the available endpoints:
curl https://oc.example.com/oauth-server/oauth-authorization-server -
Verify that the signing keys are available:
curl https://oc.example.com/oauth-server/jwks -
Verify that a controller advertises OAuth:
curl https://controller-a.example.com/.well-known/oauth-protected-resource -
After connecting an MCP agent as described in Connect the MCP agent, verify that you are prompted to sign in through OAuth instead of entering an API token.
If verification fails, refer to Resolve OAuth configuration issues.