Explanation

Cognito tokens in Trax

Amazon Cognito user pools issue tokens that look like any other JWT but do not follow the usual conventions for audience and token type, which is why Trax ships a Cognito helper rather than pointing AddTraxJwtAuth at the pool and stopping there. The helper's members are on UseCognito.

ID tokens and access tokens

Cognito issues two tokens per session. An ID token carries who the user is (email, name, the federated identities) and puts the app client id in aud, as OIDC expects. An access token carries OAuth scopes, puts the app client id in a client_id claim instead, and has no aud at all. A standard JWT validator checks aud, so it accepts the ID token and refuses the access token, while many client SDKs send the access token by default.

UseCognito replaces the audience check with one that knows both shapes, and checks the token_use claim so a host that asked for only one shape does not accept the other. It also refuses a token that claims the access shape (client_id) without token_use: Cognito always stamps token_use on an access token, so a token without it is not one, and the client_id claim alone vouches for nothing. That rule is scoped to tokens carrying client_id, so an internal issuer's tokens on the same host, which carry neither claim, are unaffected.

Which shape to accept is the host's choice: both, when different clients send different tokens; access only, when the clients send access tokens and nothing reads profile claims; ID only, when the host needs the user's attributes.

Federation

A user pool can broker Google, Apple, SAML and other OIDC providers. The tokens still come from the pool: the pool is the issuer, sub is the Cognito-assigned UUID, and an identities claim, a JSON array, describes the upstream provider. So the Trax side does not change with federation: it validates one issuer and identifies users by the pool's sub. CognitoJwtPrincipalResolver surfaces the provider as an identity_provider claim for code that wants to know how the user signed in.

A user who signs in through two providers is two pool users unless the pool links them, which is Cognito configuration (typically a PreSignUp trigger that calls AdminLinkProviderForUser), not Trax's.

Local development and tests

A Cognito user pool cannot run locally, so Trax.Api.Auth.Jwt.Cognito.Issuer mints tokens with the same claims a pool emits. A local stand-in service, or a test, signs tokens with it and serves its key, and the host keeps the same UseCognito validation for real and local tokens. The package covers tokens and refresh-token rotation only; sign-up, hosted UI, MFA and triggers are the pool's own API, which a stand-in builds itself if it needs them. Minting is on CognitoTokenIssuer, and a test walkthrough on Test JWT authentication.

SDK Reference

UseCognito | CognitoDefaults | CognitoTokenIssuer