import { Request, Response } from 'express'; import { OAuth2Logger } from '../utils/logger'; /** * OAuth2 client object */ export interface OAuth2Client { id: string | number; secret: string; scope: string[]; grants: string[]; } /** * OAuth2 access token object */ export interface OAuth2AccessToken { token: string; user_id: string | number; client_id: string | number; scope: string; expires_at: Date; } /** * OAuth2 authorization code object */ export interface OAuth2Code { code: string; expires_at: Date; user_id: string | number; client_id: string | number; scope: string; nonce?: string; code_challenge_method?: 'plain' | 'S256'; code_challenge?: string; } /** * OAuth2 refresh token object */ export interface OAuth2RefreshToken { token: string; user_id: string | number; client_id: string | number; scope: string; } /** * OAuth2 implicit user model */ export interface OAuth2User { id: string | number; username: string; password: string; } /** * OAuth2 token response */ export interface OAuth2TokenResponse { id_token?: string; access_token?: string; refresh_token?: string; expires_in?: number; token_type?: string; state?: string; } /** * OAuth2 access token adapter model */ export interface OAuth2AccessTokenAdapter { /** * Static time-to-live in seconds for access token */ ttl: number; /** * Get the token string from an access token object */ getToken: (token: OAuth2AccessToken) => string; /** * Create a new access token */ create: ( userId: string | number | null, clientId: string | number, scope: string | string[], ttl: number ) => Promise; /** * Fetch an access token by the token string from the database */ fetchByToken: ( token: OAuth2AccessToken | string ) => Promise; /** * Check the time-to-live value */ checkTTL: (token: OAuth2AccessToken) => boolean; /** * Get the time-to-live value from a token object */ getTTL: (token: OAuth2AccessToken) => number; /** * Fetch an access token by user ID and client ID from the database */ fetchByUserIdClientId: ( userId: string | number, clientId: string | number ) => Promise; } /** * OAuth2 client adapter model */ export interface OAuth2ClientAdapter { /** * Get client ID from client object */ getId: (client: OAuth2Client) => string | number; /** * Get client object from the database by client ID */ fetchById: (id: string | number) => Promise; /** * Check the client secret */ checkSecret: (client: OAuth2Client, secret: string) => boolean; /** * Check grant type */ checkGrantType: (client: OAuth2Client, grant: string) => boolean; /** * Get the redirect uri of a client */ hasRedirectUri: (client: OAuth2Client) => Promise; /** * Check the redirect uri against a client */ checkRedirectUri: ( client: OAuth2Client, redirectUri: string ) => Promise; /** * Transform the scope into a string array of scopes */ transformScope: (scope: string | string[]) => string[]; /** * Check scopes against client */ checkScope: (client: OAuth2Client, scope: string[]) => boolean; } /** * OAuth2 response code adapter model */ export interface OAuth2CodeAdapter { /** * Static time-to-live in seconds for code */ ttl: number; /** * Create a new code */ create: ( userId: string | number, clientId: string | number, scope: string | string[], ttl: number, nonce?: string, code_challenge?: string, code_challenge_method?: 'plain' | 'S256', ) => Promise; /** * Fetch a code by the code string from the database */ fetchByCode: (code: OAuth2Code | string) => Promise; /** * Remove a code */ removeByCode: (code: string | OAuth2Code) => Promise; /** * Get user ID from a code object */ getUserId: (code: OAuth2Code) => string | number; /** * Get client ID from a code object */ getClientId: (code: OAuth2Code) => string | number; /** * Get scope from a code object */ getScope: (code: OAuth2Code) => string; /** * Check the time-to-live value */ checkTTL: (code: OAuth2Code) => boolean; /** * Get PCKE info */ getCodeChallenge?: (code: OAuth2Code) => { method: 'plain' | 'S256'; challenge: string; } } /** * OAuth2 refresh token adapter model */ export interface OAuth2RefreshTokenAdapter { /** * Invalidate all previous refresh tokens for user/client when new one is issued. */ invalidateOld: boolean; /** * Create a new refresh token */ create: ( userId: string | number, clientId: string | number, scope: string | string[] ) => Promise; /** * Fetch a token from the database */ fetchByToken: ( token: OAuth2RefreshToken | string ) => Promise; /** * Remove refresh token by user ID and client ID */ removeByUserIdClientId: ( userId: string | number, clientId: string | number ) => Promise; /** * Remove token by the token itself */ removeByRefreshToken: (token: string) => Promise; /** * Get user ID from token */ getUserId: (token: OAuth2RefreshToken) => string | number; /** * Get client ID from token */ getClientId: (token: OAuth2RefreshToken) => string | number; /** * Get scope from token */ getScope: (token: OAuth2RefreshToken) => string; } /** * OAuth2 user adapter model */ export interface OAuth2UserAdapter { /** * Get user ID */ getId: (user: OAuth2User) => string | number; /** * Get user from the database by ID */ fetchById: (id: string | number) => Promise; /** * Fetch a user from the database by username */ fetchByUsername: (username: string) => Promise; /** * Check user's password for implicit grant */ checkPassword: (user: OAuth2User, password: string) => Promise; /** * Fetch the user from the express request */ fetchFromRequest: (req: Request) => Promise; /** * Check if the user has already consented to this client and the scopes. Return false to force a decision. */ consented: ( userId: string | number, clientId: string | number, scope: string | string[] ) => Promise; /** * Save a consent */ consent: ( userId: string | number, clientId: string | number, scope: string | string[] ) => Promise; } /** * Adapter for managing the `openid` scope. */ export interface JWTAdapter { /** * Issue a new ID token for user. * @param user User data object obtained from the User adapter, must implement `OAuth2User` interface. * @param scope String-list of scopes (usually used to determine the claims) * @param nonce Cryptographic key passed to the authentication request, *must* be passed along as a claim. */ issueIdToken: ( user: OAuth2User, client: OAuth2Client, scope: string[], nonce?: string ) => Promise; } /** * Render the OAuth2 decision page */ export type RenderOAuth2Decision = ( req: Request, res: Response, client: OAuth2Client, scope: string[], user: OAuth2User, redirectUri: string ) => void; /** * OAuth2 adapter model */ export interface OAuth2AdapterModel { accessToken: OAuth2AccessTokenAdapter; refreshToken: OAuth2RefreshTokenAdapter; user: OAuth2UserAdapter; client: OAuth2ClientAdapter; code: OAuth2CodeAdapter; jwt?: JWTAdapter; } /** * OAuth2 adapter */ export interface OAuth2 { /** * Adapter for the OAuth2 data models. */ model: OAuth2AdapterModel; /** * Logger wrapper, use a logger of your choice by calling `logger.setLogger(...)`. * To disable, use `logger.setLogLevel('none')`. */ logger: OAuth2Logger; /** * Render function for the OAuth2 decision page */ decision: RenderOAuth2Decision; }