/** * @module * * Implements the OAuth 2.0 Device Authorization Grant (RFC 8628), allowing * input-constrained devices (e.g. smart TVs, CLI tools) to obtain access tokens * by having the user complete authorization on a secondary device. * * @see https://datatracker.ietf.org/doc/html/rfc8628 */ import { OAuth2Error } from "../errors.js"; import { TokenTypeValidationResponse } from "../token_types/types.js"; import { OAuth2Client } from "../types.js"; import { OAuth2AccessTokenError, OAuth2AccessTokenResult, OAuth2Flow, OAuth2FlowOptions, OAuth2FlowTokenResponse, OAuth2GenerateAccessTokenFromRefreshTokenFunction, OAuth2GetClientFunction, OAuth2GrantModel, OAuth2RefreshTokenGrantContext, OAuth2RefreshTokenRequest } from "./flow.js"; /** * Marker interface for the Device Authorization grant type. * * @see https://datatracker.ietf.org/doc/html/rfc8628 */ export interface DeviceAuthorizationGrant { /** The grant type identifier. */ readonly grantType: "urn:ietf:params:oauth:grant-type:device_code"; } /** * Validation context for the device authorization grant, * passed to the model's `generateAccessToken()` method to produce * a token with appropriate lifetime, type, etc. */ export interface DeviceAuthorizationGrantContext { /** The authenticated client polling the token endpoint. */ client: OAuth2Client; /** The grant type identifier. Always `"urn:ietf:params:oauth:grant-type:device_code"`. */ grantType: "urn:ietf:params:oauth:grant-type:device_code"; /** The token type prefix (e.g. `"Bearer"`, `"DPoP"`). */ tokenType: string; /** The access token lifetime in seconds. */ accessTokenLifetime: number; /** The device code being polled. */ deviceCode: string; /** The origin of the request, used for validation and security purposes. */ origin: string; /** The result of the token type validation. */ tokenTypeValidation: TokenTypeValidationResponse; } /** * Raw token request parameters for the device code grant. */ export interface DeviceAuthorizationTokenRequest { /** The client identifier. */ clientId: string; /** The grant type value. Always `"urn:ietf:params:oauth:grant-type:device_code"`. */ grantType: "urn:ietf:params:oauth:grant-type:device_code"; /** The device code previously issued by the device authorization endpoint. */ deviceCode: string; /** The client secret, if the client is confidential. */ clientSecret?: string; /** The origin of the request, used for validation and security purposes. */ origin: string; /** The result of the token type validation. */ tokenTypeValidation: TokenTypeValidationResponse; /** The client authentication method used for this request, if any. */ clientAuthMethod?: string | undefined; /** The client authentication data extracted from the request, if any. */ clientAuthData?: Partial | undefined; } /** * Validation context for the device authorization endpoint, * passed to the model's `generateDeviceCode()` method. */ export interface DeviceAuthorizationEndpointContext { /** The client requesting device authorization. */ client: OAuth2Client; /** The validated scopes requested by the client. */ scope: string[]; /** The origin of the request, used for validation and security purposes. */ origin: string; } /** * Raw authentication request parameters for the device authorization endpoint. */ export interface DeviceAuthorizationEndpointRequest { /** The client identifier. */ clientId: string; /** The client secret, if the client is confidential. */ clientSecret?: string; /** The requested scopes, if provided. */ scope?: string[]; /** The origin of the request, used for validation and security purposes. */ origin: string; } /** * The successful response from `processAuthorization()`, containing the * device code, user code, and verification endpoints to return to the device. * * @template C - The device authorization endpoint context type. * * @see https://datatracker.ietf.org/doc/html/rfc8628#section-3.2 */ export interface DeviceAuthorizationEndpointCodeResponse { /** The authorization endpoint context associated with this device code. */ context: C; /** The device verification code. Opaque to the end-user. */ deviceCode: string; /** The end-user verification code to be displayed to and entered by the user. */ userCode: string; /** The verification URI the user should visit to enter the user code (`verification_uri`). */ verificationEndpoint: string; /** The verification URI with the user code pre-filled (`verification_uri_complete`). */ verificationEndpointComplete: string; /** Discriminator ensuring this is not an error response. */ error?: never; /** Additional application-specific fields. */ [key: string]: unknown; } /** * The union of all possible outcomes from `handleAuthorizationEndpoint()`. * * - `POST / device_code`: Device and user codes were successfully generated. * - `error`: A protocol error occurred. * * @template C - The device authorization endpoint context type. */ export type DeviceAuthorizationEndpointResponse = { method: "POST"; type: "device_code"; deviceCodeResponse: DeviceAuthorizationEndpointCodeResponse; } | { type: "error"; error: OAuth2Error; client?: OAuth2Client; }; /** * The result of `processAuthorization()`. * * - `device_code`: Device and user codes were successfully generated. * - `error`: A protocol error occurred. * * @template C - The device authorization endpoint context type. */ export type DeviceAuthorizationProcessResponse = { type: "device_code"; deviceCodeResponse: DeviceAuthorizationEndpointCodeResponse; } | { type: "error"; error: OAuth2Error; client?: OAuth2Client; }; /** * The access token result shape for the device authorization grant. * Extends the base result with optional refresh token, scope, and ID token fields. */ export interface DeviceAuthorizationAccessTokenResult extends OAuth2AccessTokenResult { /** * The scopes granted with this token. Returned to the client in the token response. */ scope?: string[]; /** A refresh token to include in the token response, if applicable. */ refreshToken?: string; /** * For OpenID Connect, an ID token can also be returned from the token endpoint when * exchanging the device code for tokens, and it should be included in the access token * result so that it can be returned to the client in the token response. * * @see https://openid.net/specs/openid-connect-core-1_0.html#TokenEndpoint */ idToken?: string; } /** * An error result returned by `generateAccessToken()` during device code polling, * representing one of the RFC 8628-defined polling error states. * * Return this instead of throwing to signal transient conditions (e.g. pending, slow down) * that the device should handle by adjusting its polling behaviour. * * @see https://datatracker.ietf.org/doc/html/rfc8628#section-3.5 */ export interface DeviceAuthorizationAccessTokenError extends OAuth2AccessTokenError { /** * The RFC 8628 error code describing why the token cannot be issued yet. * * - `authorization_pending`: The user has not yet completed authorization. * - `slow_down`: The device is polling too frequently; increase the interval. * - `expired_token`: The device code has expired; restart the flow. * - `access_denied`: The user denied the authorization request. * - `invalid_request`: The request is malformed. */ error: "authorization_pending" | "slow_down" | "expired_token" | "access_denied" | "invalid_request"; } /** * A function that generates a device code and user code for a device authorization request. * * Should persist the codes along with the associated context (client, scope, etc.) for * later lookup when the device polls the token endpoint or the user visits the verification URI. * * @template TContext - The device authorization endpoint context type. * * @param context - The validated device authorization endpoint context. * @returns An object with `deviceCode` and `userCode`, or `undefined` on failure. * * @see https://datatracker.ietf.org/doc/html/rfc8628#section-3.2 */ export interface GenerateDeviceCodeFunction { (context: TContext): Promise<{ deviceCode: string; userCode: string; } | undefined> | { deviceCode: string; userCode: string; } | undefined; } /** * The result of `getDeviceAuthorizationEndpointContext()` - the first step of * the device authorization endpoint pipeline. * * @template C - The device authorization endpoint context type. */ export type DeviceAuthorizationInitiationResponse = { success: true; context: C; } | { success: false; error: OAuth2Error; }; /** * Model interface that must be implemented by the consuming application * to provide persistence for clients and tokens related to the device authorization grant. */ export interface DeviceAuthorizationModel extends OAuth2GrantModel { /** * Retrieve and validate the client for a device authorization or refresh token request. * * When `tokenRequest.grantType === "urn:ietf:params:oauth:grant-type:device_code"`, implementations MUST: * 1. Verify the `deviceCode` is valid and has not already been used (one-time use). * 2. Verify the `clientId` matches the client that requested the device code. * 3. Optionally, verify the `clientSecret` if the client is confidential. */ getClient: OAuth2GetClientFunction; /** * Retrieve and validate the client for a device authorization endpoint request. * Should verify the `clientId` is registered and permitted to use this grant type. */ getClientForAuthentication: OAuth2GetClientFunction; /** * Looks up the device code associated with a given user code, as entered by the * end-user at the verification URI. * * @param userCode - The user code entered by the end-user. * @returns The associated `deviceCode` and `client`, or `undefined` if the user code is invalid. */ verifyUserCode: (userCode: string) => Promise<{ deviceCode: string; client: OAuth2Client; } | undefined> | { deviceCode: string; client: OAuth2Client; } | undefined; /** * Generates a device code and user code for the given device authorization context. * Should persist both codes for later lookup. * See {@link GenerateDeviceCodeFunction} for the full contract. */ generateDeviceCode: GenerateDeviceCodeFunction; /** * Generates a new access token from a refresh token. * Optional - only implement if the flow supports refresh token grants. */ generateAccessTokenFromRefreshToken?: OAuth2GenerateAccessTokenFromRefreshTokenFunction; } /** * Options for configuring the device authorization grant flow. */ export interface DeviceAuthorizationFlowOptions extends OAuth2FlowOptions { /** The model implementation providing client lookup, code generation, and token generation. */ model: DeviceAuthorizationModel; /** The URL of the device authorization endpoint. Defaults to `"/device_authorization"`. */ authorizationEndpoint?: string; /** The URL of the user code verification endpoint. Defaults to `"/verify_user_code"`. */ verificationEndpoint?: string; } /** * Abstract base class for the Device Authorization flow. * * Provides the full request handling pipeline for the device authorization endpoint * (`processAuthorization`, `handleAuthorizationEndpoint`) and the token endpoint * (`initiateToken`, `token`), as well as a `verifyUserCode()` helper for the * verification endpoint. * * Subclasses must implement `toOpenAPISecurityScheme()`. * * @see https://datatracker.ietf.org/doc/html/rfc8628 */ export declare abstract class AbstractDeviceAuthorizationFlow extends OAuth2Flow implements DeviceAuthorizationGrant { readonly grantType: "urn:ietf:params:oauth:grant-type:device_code"; protected readonly model: DeviceAuthorizationModel; protected authorizationEndpoint: string; protected verificationEndpoint: string; constructor(options: DeviceAuthorizationFlowOptions); /** * Sets the URL of the device authorization endpoint. * * @param url - The device authorization endpoint URL (absolute or relative). */ setAuthorizationEndpoint(url: string): this; /** * Returns the URL of the device authorization endpoint. */ getAuthorizationEndpoint(): string; /** * Sets the URL of the user code verification endpoint. * * @param url - The verification endpoint URL (absolute or relative). */ setVerificationEndpoint(url: string): this; /** * Returns the URL of the user code verification endpoint. */ getVerificationEndpoint(): string; protected getDeviceAuthorizationEndpointContext(request: Request): Promise; /** * Processes a `POST` request to the device authorization endpoint. * * Validates the client, resolves scopes, and calls `model.generateDeviceCode()`. * Returns the device code, user code, and verification endpoints on success. * * @param request - The incoming `POST` request to the device authorization endpoint. * @returns The process response - device codes on success, or an error. */ processAuthorization(request: Request): Promise; /** * Unified handler for `POST` requests to the device authorization endpoint. * * Delegates to `processAuthorization()` and wraps the result with the HTTP method. * Returns an error response for any method other than `POST`. * * @param request - The incoming HTTP request to the device authorization endpoint. * @returns The endpoint response - a discriminated union of all possible outcomes. */ handleAuthorizationEndpoint(request: Request): Promise; /** * Verifies a user code at the verification endpoint. * * Accepts either the raw user code string or an HTTP request with a `user_code` * query parameter. Delegates to `model.verifyUserCode()`. * * @param userCode - The user code string entered by the end-user. * @returns The associated device code and client on success, or a failure with an error. */ verifyUserCode(userCode: string): Promise<{ success: true; deviceCode: string; client: OAuth2Client; } | { success: false; error: OAuth2Error; }>; /** * Verifies a user code submitted via an HTTP request to the verification endpoint. * * Extracts the `user_code` from the request's query string and delegates to * `model.verifyUserCode()`. * * @param request - The incoming HTTP request with a `user_code` query parameter. * @returns The associated device code and client on success, or a failure with an error. */ verifyUserCode(request: Request): Promise<{ success: true; deviceCode: string; client: OAuth2Client; } | { success: false; error: OAuth2Error; }>; /** * Validates the token endpoint request (both device code and refresh token grant types) * and returns the resolved grant context without yet generating tokens. * * Useful when you need to inspect the context before deciding how to generate tokens. * Most callers should use `token()` directly instead. * * @param request - The incoming token endpoint HTTP request. * @returns The grant context on success, or a failure with an error. */ initiateToken(request: Request): Promise<{ success: true; context: DeviceAuthorizationGrantContext | OAuth2RefreshTokenGrantContext; } | { success: false; error: OAuth2Error; }>; /** * Handles a token endpoint request for the device code grant (or refresh token grant). * * Validates the device code and calls `model.generateAccessToken()`. For device code * polling, maps RFC 8628 error codes (e.g. `authorization_pending`, `slow_down`) to * the appropriate OAuth 2.0 error responses. * * @param request - The incoming token endpoint HTTP request. * @returns A token response with the generated access token, or a failure with an error. */ token(request: Request): Promise; } /** * Concrete Device Authorization flow implementation. * * Extends {@link AbstractDeviceAuthorizationFlow} with an OpenAPI security scheme * definition for the `deviceAuthorization` OAuth 2.0 flow type. * * @see https://datatracker.ietf.org/doc/html/rfc8628 */ export declare class DeviceAuthorizationFlow extends AbstractDeviceAuthorizationFlow { /** * Returns the OpenAPI security scheme definition for this flow. * Uses the `oauth2` scheme type with a `deviceAuthorization` flow. * * @returns An object keyed by the security scheme name with the scheme definition. */ toOpenAPISecurityScheme(): Record; tokenUrl: string; }; }; }>; } //# sourceMappingURL=device_authorization.d.ts.map