keycloak setting up mcp cimd profile

In this example, we will be setting up our mcp authentication using Keycloak CIMD using vscode desktop. 

Let's get our keycloak instance up and running. 

docker run -p 8080:8080 -e KC_FEATURES=cimd -e KC_BOOTSTRAP_ADMIN_USERNAME=admin -e KC_BOOTSTRAP_ADMIN_PASSWORD=admin quay.io/keycloak/keycloak:latest start-dev

Then setup follow these steps here to configure vscode desktop

Setting up the client profile for VS Code desktop

  1. Navigate to Realm Settings → Client Policies → Profiles tab.

  2. Click Create client profile.

  3. Give the profile a name such as vscode-cimd-profile and click Save.

  4. Click Add executor and select client-id-metadata-document from the list.

  5. Configure the executor with the following options:

    • Allow http scheme: OFF

    • Trusted domains: vscode.dev, 127.0.0.1, code.visualstudio.com (This option is applied not only to the client_id URL but also to the URL-valued properties of the Client ID Metadata Document, such as client_uri, logo_uri, tos_uri, policy_uri, and jwks_uri. VS Code desktop’s Client ID Metadata Document includes a logo_uri property whose value is a URL on code.visualstudio.com. Therefore, this domain must be included in the trusted domains list.)

    • Restrict same domain: OFF (VS Code desktop uses a localhost redirect URI such as http://127.0.0.1:<port>/callback, which is not on the same domain as vscode.dev)

    • Only Allow Confidential Client: OFF (VS Code desktop is a public client)

  6. Click Save.

Setting up the client policy for VS Code desktop

  1. Navigate to Realm Settings → Client Policies → Policies tab.

  2. Click Create client policy.

  3. Give the policy a name such as vscode-cimd-policy and click Save.

  4. Under Conditions, click Add condition and select client-id-uri from the list.

  5. Configure the condition with the following options:

    • URI scheme: https

    • Trusted domains: vscode.dev

  6. Click Save.

  7. Under Associated client profiles, add the vscode-cimd-profile profile created in the previous step.

  8. Click Save.


And then my executor setup are as follows




This is my vscode-cimd-policy looks like 

And my client-id-uri looks like:



We can see that vscode's has the followings: client-metadata.json

Please note your configuration must match 



If you don't have the trusted domain configure, then you will run into an issue:



Fire up your brownser and then paste the following in your brower url. 

http://localhost:8080/realms/master/protocol/openid-connect/auth?client_id=https%3A%2F%2Fvscode.dev%2Foauth%2Fclient-metadata.json&response_type=code&redirect_uri=http%3A%2F%2F127.0.0.1%3A33418%2F&resource=http%3A%2F%2Flocalhost%3A8080%2Fmcp

Here is the URL decoded into a clean, human-readable format:

client_id     = https://vscode.dev/oauth/client-metadata.json

response_type = code

redirect_uri  = http://127.0.0.1:33418/

resource      = http://localhost:8080/mcp

And then keycloak will ask you for your username and password. Please enter your username and password and then you will see the following screen. 



You will noticed that we didn't pass any of our configration details here except the domain and fortunately that's all it needs. 

The Flow: How Your Configuration Works

When you open that URL, here's what happens behind the scenes:

1. Browser sends request to Keycloak:
   GET /auth?client_id=https://vscode.dev/oauth/client-metadata.json&...

2. Keycloak receives it and asks: "Is this a valid client?"
   ❌ It's NOT a pre-registered client in the database
   ✅ But it IS a URL (the client_id parameter)

3. Keycloak checks its CLIENT POLICIES:
   ├─ "Is this a URI scheme?" → YES (https://)
   ├─ "Is the domain trusted?" → Check against vscode.dev
   └─ If YES to both → Trigger the associated PROFILE

4. The PROFILE (with client-id-metadata-document executor) runs:
   ├─ Recognizes client_id is a URL
   ├─ Fetches https://vscode.dev/oauth/client-metadata.json
   ├─ Validates the metadata (checks redirect_uri, grant types, etc.)
   ├─ Extracts the allowed redirect URIs from the metadata
   └─ Uses those to validate your redirect_uri parameter

5. Keycloak validates:
   ✅ redirect_uri (http://127.0.0.1:33418/) matches metadata's allowed list
   ✅ resource parameter is present
   ✅ All OAuth 2.0 requirements met

6. Shows login page ✅


Why It Works

StepComponentAction
1Client PolicyDetects client_id=https://vscode.dev/... matches the client-id-uri condition
2Client PolicyChecks if vscode.dev is in trusted domains ✅
3Associated ProfileTriggers the client-id-metadata-document executor
4ExecutorFetches the metadata JSON from that URL
5ExecutorValidates redirect_uri against the fetched metadata's redirect_uris list
6ExecutorValidates domain trust and other security checks
7KeycloakIssues token with resource as the audience

If we didn't configure anything and when are request comes into keycloak, the following workflow takes place. 

Keycloak receives: client_id=https://vscode.dev/oauth/client-metadata.json

Looks for "vscode.dev" in registered clients

Doesn't find it

❌ Rejects the request


OAuth CIMD Flow (From the Spec)

The core idea is that instead of receiving a client_id from the authorization server, the client uses an HTTPS URL as its client_id. That URL points to a JSON document containing the client's metadata — name, redirect URIs, supported grant types, and more. The authorization server fetches this document when it encounters the URL-based client_id. 

The Step-by-Step Flow (How It Should Work)

Here's what happens:

  1. The client initiates an Authorization request with its URL as the client_id (e.g., https://client.example.com/oauth-client).
  2. The authorization server recognizes the client_id as a URL and fetches it via HTTPS.
  3. The response is a JSON document containing standard OAuth client metadata.
  4. The authorization server validates the metadata, displays consent information to the user, and proceeds with the OAuth flow.
  5. Subsequent requests can use cached metadata according to HTTP caching headers







Comments

Popular posts from this blog

Windows SSH: Permissions for 'private-key' are too open

NodeJS: Error: spawn EINVAL in window for node version 20.20 and 18.20