UNPKG

@dainprotocol/oauth2-token-manager

Version:

A scalable OAuth2 token management library with multi-system support

373 lines (352 loc) 14.3 kB
interface OAuth2Config { clientId: string; clientSecret?: string; authorizationUrl: string; tokenUrl: string; redirectUri: string; scopes: string[]; usePKCE?: boolean; pkce?: boolean; additionalParams?: Record<string, string>; extraAuthParams?: Record<string, string>; responseRootKey?: string; profileUrl?: string; userInfoUrl?: string; onSuccess?: (userId: string, tokens: OAuth2Token) => Promise<void>; } interface OAuth2Token { accessToken: string; refreshToken?: string; expiresAt: Date; expiresIn?: number; tokenType: string; scope?: string; createdAt?: number; raw?: Record<string, any>; } interface AuthorizationState { state: string; codeVerifier?: string; config: OAuth2Config; createdAt: Date; metadata?: Record<string, any>; } interface UserProfile { email: string; name?: string; id?: string; avatar?: string; username?: string; raw?: Record<string, any>; } interface ProfileFetcher { /** * Fetch user profile using an access token * @param accessToken The OAuth access token * @returns Promise resolving to user profile information */ fetchProfile(accessToken: string): Promise<UserProfile>; /** * Get the profile endpoint URL for this provider * @returns The URL used to fetch user profiles */ getProfileEndpoint(): string; } declare abstract class BaseProfileFetcher { protected profileEndpoint: string; constructor(profileEndpoint: string); /** * Fetch user profile information from the OAuth provider * @param accessToken The OAuth access token * @returns Promise resolving to standardized user profile */ fetchUserInfo(accessToken: string): Promise<UserProfile>; /** * Map the raw API response to our standardized UserProfile structure * Override this method to customize mapping for different providers */ protected abstract mapToUserProfile(rawData: any): UserProfile; /** * Get additional headers if needed for the profile request * Override this method to add provider-specific headers */ protected getAdditionalHeaders(): Record<string, string>; /** * Get the profile endpoint URL */ getEndpoint(): string; } /** * Simplified storage adapter interface * Only stores tokens with provider, userId, and email as key fields * Enforces uniqueness on provider + email combination */ interface StorageAdapter { saveToken(input: SaveTokenInput): Promise<StoredToken>; queryTokens(query: TokenQuery): Promise<StoredToken[]>; getToken(provider: string, email: string): Promise<StoredToken | null>; getTokenById(id: string): Promise<StoredToken | null>; getTokensByUserId(userId: string): Promise<StoredToken[]>; getTokensByEmail(email: string): Promise<StoredToken[]>; getTokensByProvider(provider: string): Promise<StoredToken[]>; getAccounts(userId: string, provider: string): Promise<StoredToken[]>; getTokensForEmail(userId: string, provider: string, email: string): Promise<StoredToken | null>; getTokens(userId: string, provider: string): Promise<StoredToken[]>; updateToken(id: string, update: UpdateTokenInput): Promise<StoredToken | null>; deleteToken(id: string): Promise<boolean>; deleteTokenByProviderEmail(provider: string, email: string): Promise<boolean>; deleteExpiredTokens(): Promise<number>; saveAuthorizationState(state: Omit<AuthorizationState, 'createdAt'>): Promise<AuthorizationState>; getAuthorizationState(state: string): Promise<AuthorizationState | null>; deleteAuthorizationState(state: string): Promise<boolean>; cleanupExpiredStates(): Promise<number>; registerProfileFetcher(providerName: string, fetcher: BaseProfileFetcher): void; getProfileFetcher(providerName: string): BaseProfileFetcher | undefined; getProfileFetchers(): Map<string, BaseProfileFetcher>; } interface StoredToken { id: string; provider: string; userId: string; email: string; token: OAuth2Token; metadata?: Record<string, any>; createdAt: Date; updatedAt: Date; } interface SaveTokenInput { provider: string; userId: string; email: string; token: OAuth2Token; metadata?: Record<string, any>; } interface UpdateTokenInput { token?: OAuth2Token; metadata?: Record<string, any>; } interface TokenQuery { id?: string; provider?: string; userId?: string; email?: string; includeExpired?: boolean; limit?: number; offset?: number; } interface ProfileBasedTokenOptions { checkProfileEmail?: boolean; replaceConflictingTokens?: boolean; mergeUserData?: boolean; } interface OAuth2Options { storage?: StorageAdapter; providers?: Record<string, OAuth2Config>; autoRefresh?: AutoRefreshOptions; } interface AutoRefreshOptions { enabled?: boolean; refreshBuffer?: number; onRefreshError?: (error: Error, token: StoredToken) => void; } interface AuthorizationOptions { provider: string; userId: string; email: string; scopes?: string[]; metadata?: Record<string, any>; usePKCE?: boolean; } interface TokenOptions { autoRefresh?: boolean; refreshBuffer?: number; expirationBuffer?: number; defaultExpiresIn?: number; } interface CallbackResult { token: StoredToken; profile?: UserProfile; } declare class OAuth2Client { private storage; private providerFactory; private providers; private providerConfigs; private now; private autoRefreshOptions; constructor(options?: OAuth2Options); /** * Register a provider configuration */ registerProvider(name: string, config: OAuth2Config): void; /** * Start OAuth2 authorization flow */ authorize(options: AuthorizationOptions): Promise<{ url: string; state: string; }>; /** * Handle OAuth2 callback */ handleCallback(code: string, state: string): Promise<CallbackResult>; /** * Get a valid access token (auto-refresh if needed) */ getAccessToken(provider: string, email: string, options?: TokenOptions): Promise<string>; /** * Get a valid token (auto-refresh if needed) */ getValidToken(provider: string, email: string, options?: TokenOptions): Promise<OAuth2Token>; /** * Query tokens with automatic refresh */ queryTokens(query: TokenQuery): Promise<StoredToken[]>; /** * Get all tokens for a user */ getTokensByUserId(userId: string): Promise<StoredToken[]>; /** * Get all tokens for an email */ getTokensByEmail(email: string): Promise<StoredToken[]>; /** * Delete a token */ deleteToken(provider: string, email: string): Promise<boolean>; /** * Delete all expired tokens */ cleanupExpiredTokens(): Promise<number>; /** * Clean up expired authorization states */ cleanupExpiredStates(): Promise<number>; private isTokenExpired; private detectProviderType; /** * Refresh tokens if they are near expiration */ private refreshTokensIfNeeded; /** * Check if a token should be refreshed */ private shouldRefreshToken; /** * Update auto-refresh options */ updateAutoRefreshOptions(options: Partial<AutoRefreshOptions>): void; } declare class InMemoryStorageAdapter implements StorageAdapter { private tokens; private states; private profileFetchers; private generateId; saveToken(input: SaveTokenInput): Promise<StoredToken>; queryTokens(query: TokenQuery): Promise<StoredToken[]>; getToken(provider: string, email: string): Promise<StoredToken | null>; getTokenById(id: string): Promise<StoredToken | null>; getTokensByUserId(userId: string): Promise<StoredToken[]>; getTokensByEmail(email: string): Promise<StoredToken[]>; getTokensByProvider(provider: string): Promise<StoredToken[]>; getAccounts(userId: string, provider: string): Promise<StoredToken[]>; getTokensForEmail(userId: string, provider: string, email: string): Promise<StoredToken | null>; getTokens(userId: string, provider: string): Promise<StoredToken[]>; updateToken(id: string, update: UpdateTokenInput): Promise<StoredToken | null>; deleteToken(id: string): Promise<boolean>; deleteTokenByProviderEmail(provider: string, email: string): Promise<boolean>; deleteExpiredTokens(): Promise<number>; saveAuthorizationState(state: Omit<AuthorizationState, 'createdAt'>): Promise<AuthorizationState>; getAuthorizationState(state: string): Promise<AuthorizationState | null>; deleteAuthorizationState(state: string): Promise<boolean>; cleanupExpiredStates(): Promise<number>; registerProfileFetcher(providerName: string, fetcher: BaseProfileFetcher): void; getProfileFetcher(providerName: string): BaseProfileFetcher | undefined; getProfileFetchers(): Map<string, BaseProfileFetcher>; } interface AuthorizationUrlStrategy { generateAuthorizationUrl(config: OAuth2Config, state: string, codeChallenge?: string): string; } interface TokenExchangeStrategy { exchangeCodeForToken(code: string, config: OAuth2Config, codeVerifier?: string): Promise<OAuth2Token>; refreshToken(refreshToken: string, config: OAuth2Config): Promise<OAuth2Token>; } declare abstract class OAuth2Provider { protected config: OAuth2Config; protected authUrlStrategy: AuthorizationUrlStrategy; protected tokenStrategy: TokenExchangeStrategy; protected profileFetcher?: BaseProfileFetcher; constructor(config: OAuth2Config, authUrlStrategy?: AuthorizationUrlStrategy, tokenStrategy?: TokenExchangeStrategy, profileFetcher?: BaseProfileFetcher); protected abstract createAuthorizationUrlStrategy(): AuthorizationUrlStrategy; protected abstract createTokenExchangeStrategy(): TokenExchangeStrategy; fetchProfile(accessToken: string): Promise<UserProfile>; getProfileEndpoint(): string; setProfileFetcher(profileFetcher: BaseProfileFetcher): void; hasProfileFetcher(): boolean; generateAuthorizationUrl(state: string, codeChallenge?: string): string; exchangeCodeForToken(code: string, codeVerifier?: string): Promise<OAuth2Token>; refreshToken(refreshToken: string): Promise<OAuth2Token>; } type ProviderType = 'google' | 'github' | 'microsoft' | 'outlook' | 'facebook' | 'generic'; interface ProviderFactory { createProvider(type: ProviderType, config: OAuth2Config): OAuth2Provider; } declare class StandardTokenExchangeStrategy implements TokenExchangeStrategy { protected buildUrlParams(params: Record<string, string | undefined>): string; exchangeCodeForToken(code: string, config: OAuth2Config, codeVerifier?: string): Promise<OAuth2Token>; refreshToken(refreshToken: string, config: OAuth2Config): Promise<OAuth2Token>; } declare class StandardAuthorizationUrlStrategy implements AuthorizationUrlStrategy { protected buildUrlParams(params: Record<string, string | undefined>): string; generateAuthorizationUrl(config: OAuth2Config, state: string, codeChallenge?: string): string; } declare class GenericOAuth2Provider extends OAuth2Provider { constructor(config: any, authUrlStrategy?: AuthorizationUrlStrategy, tokenStrategy?: TokenExchangeStrategy, profileFetcher?: BaseProfileFetcher); protected createAuthorizationUrlStrategy(): AuthorizationUrlStrategy; protected createTokenExchangeStrategy(): TokenExchangeStrategy; } declare class GoogleProfileFetcher extends BaseProfileFetcher { constructor(); mapToUserProfile(rawData: any): UserProfile; } declare class GitHubProfileFetcher extends BaseProfileFetcher { constructor(); protected mapToUserProfile(rawData: any): UserProfile; protected getAdditionalHeaders(): Record<string, string>; } declare class MicrosoftProfileFetcher extends BaseProfileFetcher { constructor(); protected mapToUserProfile(rawData: any): UserProfile; } interface ProfileMapping { email: string; name?: string; id?: string; avatar?: string; username?: string; } declare class GenericProfileFetcher extends BaseProfileFetcher { private mapping?; private additionalHeaders?; constructor(profileEndpoint: string, mapping?: ProfileMapping | undefined, additionalHeaders?: Record<string, string> | undefined); protected mapToUserProfile(rawData: any): UserProfile; protected getAdditionalHeaders(): Record<string, string>; private getNestedProperty; } interface ProfileFetcherOptions { profileUrl?: string; profileMapping?: ProfileMapping; profileHeaders?: Record<string, string>; } declare class ProfileFetcherFactory { static createProfileFetcher(providerType: ProviderType, config: OAuth2Config, options?: ProfileFetcherOptions): BaseProfileFetcher; static registerCustomProfileFetcher(providerName: string, profileFetcher: BaseProfileFetcher): void; private static customFetchers; static getCustomProfileFetcher(providerName: string): BaseProfileFetcher | undefined; } declare const createCodeVerifier: () => string; declare const createCodeChallenge: (verifier: string) => string; declare const generateState: () => string; declare const seal: <T>(d: T, key: string) => Promise<string>; declare const unseal: <T>(s: string, key: string) => Promise<T>; export { type AuthorizationOptions, type AuthorizationState, type AuthorizationUrlStrategy, type AutoRefreshOptions, BaseProfileFetcher, type CallbackResult, GenericOAuth2Provider, GenericProfileFetcher, GitHubProfileFetcher, GoogleProfileFetcher, InMemoryStorageAdapter, MicrosoftProfileFetcher, OAuth2Client, type OAuth2Config, type OAuth2Options, OAuth2Provider, type OAuth2Token, type ProfileBasedTokenOptions, type ProfileFetcher, ProfileFetcherFactory, type ProfileFetcherOptions, type ProfileMapping, type ProviderFactory, type ProviderType, type SaveTokenInput, StandardAuthorizationUrlStrategy, StandardTokenExchangeStrategy, type StorageAdapter, type StoredToken, type TokenExchangeStrategy, type TokenOptions, type TokenQuery, type UpdateTokenInput, type UserProfile, createCodeChallenge, createCodeVerifier, generateState, seal, unseal };