import type { HttpContext } from '@adonisjs/core/http'; import { Oauth2Client } from '@poppinss/oauth-client/oauth2'; import { type AllyUserContract, type Oauth2AccessToken, type Oauth2DriverConfig, type ApiRequestContract, type AllyDriverContract, type RedirectRequestContract } from '../types.ts'; import { RedirectRequest } from '../redirect_request.ts'; /** * Abstract base class for implementing OAuth2 social authentication drivers. * Extends the OAuth2 client to provide AdonisJS-specific functionality like * CSRF protection, state management, and integration with HTTP context. * * @example * ```ts * export class CustomDriver extends Oauth2Driver { * protected stateCookieName = 'custom_oauth_state' * protected stateParamName = 'state' * protected errorParamName = 'error' * protected codeParamName = 'code' * protected authorizeUrl = 'https://provider.com/oauth/authorize' * protected accessTokenUrl = 'https://provider.com/oauth/token' * protected scopeParamName = 'scope' * protected scopesSeparator = ' ' * * async user() { * // Implementation * } * } * ``` */ export declare abstract class Oauth2Driver extends Oauth2Client implements AllyDriverContract { #private; protected ctx: HttpContext; config: Oauth2DriverConfig; /** * Whether the authorization process is stateless. When true, * state verification via cookies is disabled. */ protected isStateless: boolean; /** * The cookie name for storing the CSRF state token. Must be unique * for your driver to avoid conflicts. For example: `gh_oauth_state` */ protected abstract stateCookieName: string; /** * The cookie name for storing the PKCE code verifier. Define this property * in child classes that require PKCE. */ protected codeVerifierCookieName?: string; /** * The query parameter name for sending the state to the OAuth provider. * This is typically 'state' but varies by provider. Check the provider's * OAuth documentation. */ protected abstract stateParamName: string; /** * The query parameter name for error messages returned by the provider * after authorization redirect. This is typically 'error'. */ protected abstract errorParamName: string; /** * The query parameter name for the authorization code returned by the * provider. This is typically 'code'. */ protected abstract codeParamName: string; /** * The OAuth provider's authorization URL where users are redirected * to grant permissions. */ protected abstract authorizeUrl: string; /** * The OAuth provider's endpoint for exchanging the authorization code * for an access token. */ protected abstract accessTokenUrl: string; /** * The query parameter name for defining authorization scopes. * This is typically 'scope'. */ protected abstract scopeParamName: string; /** * The separator character for joining multiple scopes. This is * typically a space ' ' or comma ','. */ protected abstract scopesSeparator: string; /** * Fetch the user details from the OAuth provider using the * authorization code from the current request. * * @param callback - Optional callback to customize the API request * @returns A promise resolving to the authenticated user profile. */ abstract user(callback?: (request: ApiRequestContract) => void): Promise>; /** * Fetch user details using an existing access token. Useful for * verifying tokens or fetching user info for already authenticated users. * * @param token - The access token * @param callback - Optional callback to customize the API request * @returns A promise resolving to the authenticated user profile. */ abstract userFromToken(token: string, callback?: (request: ApiRequestContract) => void): Promise>; /** * Check if the current error indicates that the user denied access. * Different providers use different error codes for access denial. * * @returns `true` when the provider reported an access-denied state. */ abstract accessDenied(): boolean; /** * OAuth protocol version identifier */ version: "oauth2"; /** * Cached state value read from the cookie */ protected stateCookieValue?: string; /** * Cached PKCE code verifier value read from the cookie via * loadState */ protected codeVerifierCookieValue?: string; /** * Create a new OAuth2 driver instance. * * @param ctx - The current HTTP context * @param config - OAuth2 driver configuration */ constructor(ctx: HttpContext, config: Oauth2DriverConfig); /** * Creates a URL builder instance for constructing authorization URLs * with scope support. * * @param url - The base authorization URL * @returns A redirect request builder for the given URL. */ protected urlBuilder(url: string): RedirectRequest; /** * Loads the state value from the encrypted cookie and immediately clears * the cookie. When PKCE is enabled, it also loads the PKCE code verifier. * This must be called by child classes in their constructor. * * @example * ```ts * constructor(ctx: HttpContext, config: DriverConfig) { * super(ctx, config) * this.loadState() * } * ``` */ protected loadState(): void; /** * Returns the PKCE code verifier for building the authorization redirect. * This method is expected to create and persist the verifier for later use. * * @returns The generated PKCE code verifier or `null` when PKCE is disabled. */ protected getPkceCodeVerifierForRedirect(): string | null; /** * Returns the PKCE code verifier for the access token exchange. * This method only reads the verifier that was persisted during redirect. * * @returns The persisted PKCE code verifier or `null` when PKCE is disabled. */ protected getPkceCodeVerifierForAccessToken(): string | null; /** * Enable stateless authentication by disabling CSRF state verification. * Only use this in scenarios where state verification is not required. * * @returns The current driver instance. * * @example * ```ts * await ally.use('github').stateless().redirect() * ``` */ stateless(): this; /** * Get the authorization redirect URL without performing the redirect. * Useful when you need to manually handle the redirect or use the URL * in a different context. * * @param callback - Optional callback to customize the redirect request * @returns A promise resolving to the authorization URL. * * @example * ```ts * const url = await ally.use('github').redirectUrl((request) => { * request.scopes(['user:email']) * }) * ``` */ redirectUrl(callback?: (request: RedirectRequestContract) => void): Promise; /** * Redirect the user to the OAuth provider's authorization page. * The state parameter is automatically set for CSRF protection. * * @param callback - Optional callback to customize the redirect request * @returns A promise that resolves after the redirect response is prepared. * * @example * ```ts * await ally.use('github').redirect((request) => { * request.scopes(['user:email', 'read:org']) * request.param('allow_signup', 'false') * }) * ``` */ redirect(callback?: (request: RedirectRequestContract) => void): Promise; /** * Check if the state parameter from the callback matches the state * stored in the cookie. Returns false in stateless mode. * * @returns `true` when the state validation fails. */ stateMisMatch(): boolean; /** * Check if an error was returned by the OAuth provider. * * @returns `true` when an error exists on the callback request. */ hasError(): boolean; /** * Get the error code or message returned by the OAuth provider. * Returns 'unknown_error' if no code is present and no error was specified. * * @returns The provider error value when present. */ getError(): string | null; /** * Get the authorization code from the callback request. * * @returns The authorization code when present. */ getCode(): string | null; /** * Check if the authorization code is present in the callback request. * * @returns `true` when the callback request contains an authorization code. */ hasCode(): boolean; /** * Exchange the authorization code for an access token. This method * validates the state and checks for errors before making the request. * * @param callback - Optional callback to customize the token request * @returns A promise resolving to the access token payload. * * @example * ```ts * const token = await ally.use('github').accessToken() * ``` */ accessToken(callback?: (request: ApiRequestContract) => void): Promise; /** * Not applicable with OAuth2. Use `userFromToken` instead. * * @returns This method never returns. */ userFromTokenAndSecret(): Promise; }