diff --git a/docs/knowledge/devops-tools/aws/cognito.md b/docs/knowledge/devops-tools/aws/cognito.md index 0af4efa..94333d8 100644 --- a/docs/knowledge/devops-tools/aws/cognito.md +++ b/docs/knowledge/devops-tools/aws/cognito.md @@ -69,15 +69,41 @@ so the next app's redirect skips the login form — that is - **`name` and `picture` come in the ID token**, from the user's attributes; `picture` is only a URL, so the image must be hosted elsewhere. - **Self-signup can be off** for a private pool; users are created by an admin. -- **No Dynamic Client Registration.** Cognito cannot register clients on the fly, so it - cannot be the authorization server for a "paste a link" remote - [MCP connector](../../web-development/mcp-authorization.md) without a shim or - pre-registered client. - **Pools created with a retain removal policy** are not deleted when the stack is; delete them by hand once nothing uses them. - **Global sign-out** revokes the user's refresh tokens; access tokens already issued stay valid until they expire. +## Dynamic Client Registration for MCP + +Cognito can now let applications register their own app clients at runtime (RFC 7591), +which is what a remote [MCP connector](../../web-development/mcp-authorization.md) +needs to onboard from just a URL. It is off by default (console: user pool → +Applications → **MCP auth**). + +- **Requirements:** the Essentials or Plus feature plan, and **managed login** on every + domain of the pool. For MCP, a **resource server** whose identifier is the MCP + server's URL, with custom scopes; clients send the `resource` parameter and the access + token's `aud` is then that URL. +- **Two modes:** *open* registration (no token) and *authenticated* registration (an + initial access token from a client holding the system scope `aws.cognito/dcr/register`). + Claude's connector cannot present an initial token, so it needs open registration. +- **Discovery:** the OIDC document (`/.well-known/openid-configuration`) lists + `registration_endpoint` (`/oauth2/register`). The RFC 8414 path + `/.well-known/oauth-authorization-server` still answers 400 on the issuer, so a client + that does not fall back to OIDC discovery needs a small shim on the MCP server. +- **Cost of open registration:** anyone can create clients (they share the app-client + quota, 10,000 with DCR on); registered clients get every identity provider of the + pool and the default auth flows; there is **no consent screen**, so a user with a live + session can be signed in to a hostile client without a prompt; there is no + per-connection grant, so revoking means deleting the client (list them with + `ListUserPoolClients` and `ClientType=DCR`). AWS suggests a WAF rate limit on + `/oauth2/register`, which is an extra paid component. + +In a shared SSO pool this puts anonymous registration next to every other app, so a +dedicated pool (federating the SSO pool) or a self-run authorization server are the +alternatives when that is too open. + ## When to Use Which - Need "is this user logged in, and who are they" for your own API? → @@ -109,5 +135,5 @@ for the specific AWS resources the client needs to touch directly. direct client-side uploads. - [Single Sign-On with OIDC](../../web-development/single-sign-on-oidc.md) — several apps as clients of one pool. -- [MCP Authorization](../../web-development/mcp-authorization.md) — why a provider - without Dynamic Client Registration complicates remote MCP connectors. +- [MCP Authorization](../../web-development/mcp-authorization.md) — remote MCP + connectors: delegating to Cognito's DCR versus running your own authorization server. diff --git a/docs/knowledge/web-development/mcp-authorization.md b/docs/knowledge/web-development/mcp-authorization.md index db65637..5e3e827 100644 --- a/docs/knowledge/web-development/mcp-authorization.md +++ b/docs/knowledge/web-development/mcp-authorization.md @@ -106,17 +106,35 @@ The MCP server only validates tokens issued by a provider such as [Cognito](../devops-tools/aws/cognito.md), and points `authorization_servers` at it. - **Pros:** no token issuance code to maintain; one place for users and MFA. -- **Cons:** the provider must support what the client expects. Cognito, notably, has - **no Dynamic Client Registration**, so a connector can only work if someone - pre-registers a client and gives the assistant that client id by hand (and a shim in - front of the provider usually has to paper over the missing discovery documents). - Tokens are also issued for the whole pool, so the server must check the client and - audience to know a token was meant for it. +- **Cons:** the provider must support what the client expects, and you inherit its + defaults. Tokens are issued for the whole pool, so the server must check issuer, + audience and scope to know a token was meant for it. + +Whether a provider can onboard "paste a link" connectors depends on **Dynamic Client +Registration**. Cognito used to have none (a connector then needed a hand-registered +client id, plus a shim route on the MCP server to paper over missing discovery +documents). It now has an opt-in DCR for MCP (managed login, a resource server per MCP +server whose identifier is the MCP URL, open or authenticated registration; see +[Cognito](../devops-tools/aws/cognito.md#dynamic-client-registration-for-mcp)). That +removes the token code, but not the trade-offs below. + +**Delegating with open registration is a weaker posture:** + +- **No consent screen of your own.** A registered client chooses its own redirect + URIs, and a user who already has an SSO session can be signed in to it without a + prompt. A phishing link plus a client the attacker registered can then mint a + token. A self-run server can instead allow only the assistant vendor's callbacks + and ask "approve this app?" every time. +- **Open registration is anonymous and shared.** Anyone can create clients in the + pool (counted against its quota) unless you front it with a rate limit, and in a + shared SSO pool the clutter and the allowed scopes sit next to every other app. +- **Revocation is client deletion**, not a per-connection grant you can list. !!! tip "Rule of thumb" - "Paste a link and it works, for several different assistant accounts" means the - server must speak DCR, which in practice means it runs its own small authorization - server. Delegating to a provider is simpler when the clients are known in advance. + "Paste a link and it works, for several different assistant accounts" needs DCR. + A provider's DCR is the lowest-code way; a small self-run authorization server is + the one that gives you consent, a redirect allow-list and per-connection + revocation. Delegating is simplest when the clients are known in advance. ## Design Decisions That Matter @@ -194,8 +212,10 @@ grant row, all pointing at the approving user's id. That gives: bearer token. - The MCP server is a resource server; whether it also acts as the authorization server decides whether "just a link" onboarding is possible. -- No DCR (as in Cognito) means manual client registration; running a small - authorization server with DCR removes it. +- "Just a link" onboarding needs DCR: either the provider's (Cognito now offers one, + with open registration, no consent screen and client-deletion revocation) or a + small authorization server of your own (consent, redirect allow-list, per-grant + revocation). - Bind every grant to the approving user's id, hash all secrets, rotate refresh tokens and revoke the grant on reuse, restrict DCR, and give users a revoke page. - Validate `client_id` and `redirect_uri` before ever redirecting. @@ -209,4 +229,4 @@ grant row, all pointing at the approving user's id. That gives: - [FastMCP: Building and Deploying an MCP Server](../machine-learning/fastmcp-knowledge-base-server.md) — the server side: tools, transports, deployment. - [AWS Cognito](../devops-tools/aws/cognito.md) — the identity provider used in the - delegated variant, and its missing DCR. + delegated variant, and its opt-in DCR for MCP.