{"id":"97195e24edc3b3c99dd8fd1b08cd14d1fa4f02e5e653b077e9901a03752e67fb","pubkey":"d1678e7ef965374bbea308a1215609a78376dc158277a7d657680f9d5efd5c38","created_at":1770735280,"kind":30817,"tags":[["d","nut-21"],["title","NUT-21: Clear Authentication"],["summary","How a mint restricts its endpoints to users holding a token from an OpenID Connect service it trusts."],["s","optional"],["t","cashu"],["t","ecash"],["t","nut"],["alt","A specification: NUT-21: Clear Authentication"],["client","openspecs-import"],["published_at","1738212654"],["proxy","https://github.com/cashubtc/nuts/blob/a845dfc998abae501fc3419592d53dc995d34b12/21.md","web"],["x","55f62d8a56b507dc203a3671d04b334491fc31315ff3d322988e57e9d05e5e0d"]],"content":"# NUT-21: Clear Authentication\n\n`optional`\n\n`used in: NUT-22`\n\n---\n\nThis NUT defines a clear authentication scheme that allows operators to limit the use of their mint to registered users using the OAuth 2.0 and OpenID Connect protocols. The mint operator can protect chosen endpoints from access by requiring user authentication. Only users that provide a clear authentication token (CAT) from the specified OpenID Connect (OIDC) service can use the protected endpoints. The CAT is an Oauth 2.0 Access token (also known as the `access_token`) commonly in the form of a JWT that contains user information, a signature from the OIDC service, and an expiry time. To access protected endpoints, the wallet includes the CAT in the HTTP request header.\n\n**Note:** The primary purpose of this NUT is to restrict access to a mint by allowing registered users to obtain Blind Authentication Tokens as specified in [NUT-22][22].\n\n**Warning:** This authentication scheme breaks the user's privacy as the CAT contains user information. Mint operators SHOULD require clear authentication **only on selected endpoints**, such as those for obtaining blind authentication tokens (BATs, see [NUT-22][22]).\n\n## OpenID Connect service configuration\n\nThe OpenID Connect (OIDC) service is typically run by the mint operator (but it does not have to be). The OIDC service must be configured to meet the following criteria:\n\n- **No client secret:** The OIDC service MUST NOT use a client secret.\n- **Authorization code flow:** The OIDC service MUST enable the _authorization code flow_ with PKCE for public clients, so that an authorization code can be exchanged for an access token and a refresh token.\n- **Signature algorithm:** The OIDC service MUST support at least one of the two asymmetric JWS signature algorithms for access token and ID token signatures: `ES256` and `RS256`.\n- **Wallet redirect URLs:** To support the OpenID Connect Authorization Code flow, the OIDC service MUST allow redirect URLs that correspond to the wallets it wants to support. You can find a list of common redirect URLs for well-known Cashu wallets [here][21-SUPPL].\n- **Localhost redirect URL:** The OIDC service MUST also allow redirects to the URL `http://localhost:33388/callback`.\n- **Authentication flows:** Although, strictly speaking, this NUT does not restrict the OpenID Connect grant types that can be used to obtain a CAT, it is recommended to enable at least the `authorization_code` (Authorization Code) flow and the `urn:ietf:params:oauth:grant-type:device_code` (Device Code) flow in the `grant_types_supported` field of the `openid_discovery` configuration. The `password` (Resource Owner Password Credentials, ROPC) flow SHOULD NOT be used as it requires handling the user's credentials in the wallet application.\n\n## Mint\n\n### Signalling protected endpoints\n\nThe mint lists each protected endpoint that requires a clear authentication token (CAT) in the `MintClearAuthSetting` in its [NUT-06][06] info response:\n\n```json\n\"21\" : {\n  \"openid_discovery\": \"https://mint.com:8080/realms/nutshell/.well-known/openid-configuration\",\n  \"client_id\": \"cashu-client\",\n  \"protected_endpoints\": [\n    {\n        \"method\": \"POST\",\n        \"path\": \"/v1/auth/blind/mint\"\n    }\n  ]\n}\n```\n\n`openid_discovery` is the OpenID Connect Discovery endpoint which has all the information necessary for a client to authenticate with the service.\n\n`client_id` is the OpenID Connect Client ID that the wallet needs to use to authenticate.\n\n`protected_endpoints` is an array of objects that specify each endpoint that requires a CAT in the request headers. `method` is the HTTP method, and `path` is either:\n\n1. **Exact match**: no trailing `*` → request path MUST equal `path`\n2. **Prefix match**: ends with `*` → request path MUST start with the prefix (`*` removed)\n\nThe `*` wildcard, if present, MUST be the final character only.\n\nFor example:\n\n- `/v1/*` matches any path starting `/v1/` (all endpoints)\n- `/v1/auth/*` matches any path that starts with `/v1/auth/` (all auth endpoints)\n- `/v1/mint/*` matches any path that starts with `/v1/mint/` (all minting endpoints)\n- `/v1/mint/bolt*` matches any path starting `/v1/mint/bolt` (bolt11/12 minting endpoints)\n\nIn the example above, the `/v1/auth/blind/mint` path is the **exact match** [NUT-22][22] endpoint for obtaining blind authentication tokens (BATs).\n\n> [!CAUTION]\n> Wallets **MUST** treat mint provided `path` values as untrusted input and use exact or prefix matching only. Never use regex matching on untrusted input.\n\n### Clear authentication token verification\n\nWhen receiving a request to a protected endpoint, the mint checks the included CAT (which is a JWT) in the HTTP request header (see below in section [Wallet](#cat-in-request-header)) and verifies the JWT. To verify the JWT, the mint checks the signature of the OIDC and the expiry of the JWT.\n\nThe JWT includes a `sub` field which identifies a specific user. The `sub` identifier can, for example, be used to rate limit the user.\n\n**Note:** The JWT _MAY_ include an _audience_ field called `aud` that contains the mint's public key\n\nMore on OpenID Connect ID token validation [here](https://openid.net/specs/openid-connect-core-1_0.html#IDTokenValidation).\n\n## Wallet\n\nTo make a request to one of the `protected_endpoints` of the mint, the wallet needs to obtain a valid clear auth token (CAT) from the OIDC service. The wallet uses the `openid_discovery` URL in the `MintClearAuthSetting` from the info endpoint of the mint to authenticate with the OIDC service and obtain a CAT.\n\n### Obtaining a CAT\n\nDepending on the wallet implementation and use case, an appropriate authorization flow should be used. For mobile wallets, the Authorization Code is recommended. For command-line wallets, the Device Code flow is recommended. For headless wallets, the ROPC flow may be used.\n\nIt is recommended to use language-specific libraries that can handle OpenID Connect authentication on behalf of the user. The wallet should be able to handle and store access tokens and refresh tokens for each mint that it authenticates with. If the wallet connects to a mint for the first time, or if the refresh token is about to expire, the wallet should allow the user to log in again to obtain a new access token (`access_token`) and a new refresh token (`refresh_token`).\n\nThe `access_token` is what is referred to as a clear authentication token (CAT) throughout this document.\n\n### CAT in request header\n\nWhen making a request to the mint's endpoint, the wallet matches the requested URL with the `protected_endpoints` from the `MintClearAuthSetting` (either exact match or prefix pattern match). If the match is positive, the mint requires the wallet to provide a CAT with the request.\n\nAfter obtaining a CAT from the OIDC service, the wallet includes a valid CAT in the HTTP request header when it makes requests to one of the mint's `protected_endpoints`:\n\n```\nClear-auth: <CAT>\n```\n\nThe `CAT` is a JWT (or `access_token`) encoded with base64 that is signed by and obtained from the OIDC authority. The mint verifies the JWT as described [above](#clear-authentication-token-verification).\n\n## Error codes\n\nSee [Error Codes][errors]:\n\n- `30001`: Endpoint requires clear auth\n- `30002`: Clear authentication failed\n\n[06]: nostr:naddr1qvzqqqrcvypzp5t83el0jefhfwl2xz9py9tqnfurwmwptqnh5lt9w6q0n4006hpcqqrxuat595crv3ltsuz\n[21-SUPPL]: https://github.com/cashubtc/nuts/blob/a845dfc998abae501fc3419592d53dc995d34b12/suppl/21.md\n[22]: nostr:naddr1qvzqqqrcvypzp5t83el0jefhfwl2xz9py9tqnfurwmwptqnh5lt9w6q0n4006hpcqqrxuat595erydfxtm8\n[errors]: https://github.com/cashubtc/nuts/blob/a845dfc998abae501fc3419592d53dc995d34b12/error_codes.md\n","sig":"2ece5cc0523a99b9994fe13ae7c2ecca17216071be3b81dc8ad21f5201df5c54a2057b8bcd05a12fa574c25a4e7c150927a346c4b532a592df562283427b9a31"}