import { JSONValue } from "../values/index.js"; /** * The value exported by your Convex project in `auth.config.ts`. * * ```ts * import { AuthConfig } from "convex/server"; * * export default { * providers: [ * { * domain: "https://your.issuer.url.com", * applicationID: "your-application-id", * }, * ], * } satisfies AuthConfig; * ``` */ export type AuthConfig = { providers: AuthProvider[]; }; /** * An authentication provider allowed to issue JWTs for your app. * * See: https://docs.convex.dev/auth/advanced/custom-auth and https://docs.convex.dev/auth/advanced/custom-jwt */ export type AuthProvider = // OIDC provider | { /** * Tokens issued by the auth provider must have this application ID * in their audiences. */ applicationID: string; /** * The domain of the OIDC auth provider. */ domain: string; } // Custom JWT provider (see https://docs.convex.dev/auth/advanced/custom-jwt) | { type: "customJwt"; /** * Tokens issued by the auth provider must have this application ID * in their audiences. * * Warning: omitting applicationID is often insecure * (see https://docs.convex.dev/auth/advanced/custom-jwt#warning-omitting-applicationid-is-often-insecure). */ applicationID?: string; /** * The issuer of the JWT auth provider (e.g. `https://auth.example.com`) */ issuer: string; /** * The URL to fetch the JWKS (e.g. `https://auth.example.com/.well-known/jwks.json`) */ jwks: string; /** * The algorithm used to sign the JWT tokens. Convex currently only * supports RS256 and ES256. */ algorithm: "RS256" | "ES256"; }; /** * Information about an authenticated user, derived from a * [JWT](https://datatracker.ietf.org/doc/html/rfc7519). * * The only fields guaranteed to be present are * {@link UserIdentity.tokenIdentifier} and {@link UserIdentity.issuer}. All * remaining fields may or may not be present depending on the information given * by the identity provider. * * The explicitly listed fields are derived from the OpenID Connect (OIDC) standard fields, * see the [OIDC specification](https://openid.net/specs/openid-connect-core-1_0.html#StandardClaims) * for more information on these fields. * * Any additional fields are custom claims that may be present in the JWT, * and their type depends on your identity provider configuration. If you * know the type of the field, you can assert it in TypeScript like this * (for example as a `string`): * * ```typescript * const identity = await ctx.auth.getUserIdentity(); * if (identity === null) { * return null; * } * const customClaim = identity.custom_claim as string; * ``` * * @public */ export interface UserIdentity { /** * A stable and globally unique string for this identity (i.e. no other * user, even from a different identity provider, will have the same string.) * * JWT claims: `sub` + `iss` */ readonly tokenIdentifier: string; /** * Identifier for the end-user from the identity provider, not necessarily * unique across different providers. * * JWT claim: `sub` */ readonly subject: string; /** * The hostname of the identity provider used to authenticate this user. * * JWT claim: `iss` */ readonly issuer: string; /** * JWT claim: `name` */ readonly name?: string; /** * JWT claim: `given_name` */ readonly givenName?: string; /** * JWT claim: `family_name` */ readonly familyName?: string; /** * JWT claim: `nickname` */ readonly nickname?: string; /** * JWT claim: `preferred_username` */ readonly preferredUsername?: string; /** * JWT claim: `profile` */ readonly profileUrl?: string; /** * JWT claim: `picture` */ readonly pictureUrl?: string; /** * JWT claim: `email` */ readonly email?: string; /** * JWT claim: `email_verified` */ readonly emailVerified?: boolean; /** * JWT claim: `gender` */ readonly gender?: string; /** * JWT claim: `birthdate` */ readonly birthday?: string; /** * JWT claim: `zoneinfo` */ readonly timezone?: string; /** * JWT claim: `locale` */ readonly language?: string; /** * JWT claim: `phone_number` */ readonly phoneNumber?: string; /** * JWT claim: `phone_number_verified` */ readonly phoneNumberVerified?: boolean; /** * JWT claim: `address` */ readonly address?: string; /** * JWT claim: `updated_at` */ readonly updatedAt?: string; /** * Any custom claims. */ [key: string]: JSONValue | undefined; } export type UserIdentityAttributes = Omit< UserIdentity, // tokenIdentifier is always generated by us "tokenIdentifier" >; /** * An interface to access information about the currently authenticated user * within Convex query and mutation functions. * * @public */ export interface Auth { /** * Get details about the currently authenticated user. * * @returns A promise that resolves to a {@link UserIdentity} if the Convex * client was configured with a valid ID token, or if not, will: * + returns `null` on Convex queries, mutations, actions. * + `throw` on HTTP Actions. */ getUserIdentity(): Promise; } /** * {@link Auth} for mutations, which can also sign JWTs with this deployment's * key. * * @public */ export interface MutationAuth extends Auth { /** * Sign an ES256 JWT with this deployment's key. * * Pass the `claims` and `expiresInSeconds` values that match your use case. * * Convex populates the header and sets the `iss`, `iat` and `exp` claims. * * The `iss` is `process.env.CONVEX_CLOUD_URL` for the app and * `${process.env.CONVEX_CLOUD_URL}/components/` for a component. * * Anyone can verify these tokens against the public keys at * `${process.env.CONVEX_CLOUD_URL}/.well-known/jwks.json`. * * Claims are signed but not encrypted, so anyone holding the token can read * them. * * Prefer short token lifetimes: a token can't be revoked individually, and a * mutation can always sign a fresh one to reassert the claims. This API * allows a token to have a max expiration of 1 hour from issuance. * * Claims that start with `convex` or `cvx` (case insensitive) and the `nbf` * claim are reserved and may not be set. */ signJwt(options: SignJwtOptions): Promise; } /** * Claims that callers may not set on JWTs with {@link MutationAuth.signJwt}. */ export type ReservedJwtClaim = "iss" | "iat" | "exp" | "nbf"; /** * Every ASCII casing of `S`: `AnyCase<"cvx">` is `"cvx" | "cvX" | "cVx" | ...`. */ type AnyCase = S extends `${infer First}${infer Rest}` ? `${Lowercase | Uppercase}${AnyCase}` : S; /** * Claim names starting with `convex` or `cvx`, in any casing, are reserved * for Convex. They may not be set on JWTs with {@link MutationAuth.signJwt}. */ // NOTE: only relatively short prefixes should ever be passed below. The AnyCase // type produces 2^length string literals which can get out of hand for anything // but short strings. export type ReservedJwtClaimPrefix = AnyCase<"convex" | "cvx">; /** * Rejects claim names starting with a {@link ReservedJwtClaimPrefix}. */ // Kept as a named alias rather than inlined into SignJwtClaims: typedoc's // markdown renderer mangles template-literal index signatures into invalid // MDX, but renders a reference to a named type as plain text. type ReservedPrefixJwtClaims = { [K: `${ReservedJwtClaimPrefix}${string}`]: never; }; /** * The claims a caller passes to {@link MutationAuth.signJwt}: any JSON value, * except for the {@link ReservedJwtClaim}s and names starting with a * {@link ReservedJwtClaimPrefix}. */ export type SignJwtClaims = Record & { [K in ReservedJwtClaim]?: never; } & ReservedPrefixJwtClaims; export type SignJwtOptions = { claims?: SignJwtClaims; /** How long the token stays valid, at least 1 second and at most 1 hour. */ expiresInSeconds: number; };