Overview
The OAuthProvider interface defines the contract for implementing OAuth 2.0 authentication providers in Arraf Auth. Use this interface to create custom OAuth providers for any service that supports OAuth 2.0.
Interface Definition
The OAuthProvider interface is defined in @arraf-auth/core:
export interface OAuthProvider {
id: string
name: string
clientId: string
clientSecret: string
scopes: string[]
getAuthorizationUrl(state: string, codeVerifier?: string): string
exchangeCode(code: string, codeVerifier?: string): Promise<OAuthTokens>
getUserProfile(accessToken: string): Promise<OAuthProfile>
}
Properties
Unique identifier for the provider (e.g., “google”, “github”)
Display name for the provider (e.g., “Google”, “GitHub”)
OAuth 2.0 client ID obtained from the provider’s developer console
OAuth 2.0 client secret obtained from the provider’s developer console
Array of OAuth scopes to request from the provider
Methods
getAuthorizationUrl
Generates the OAuth authorization URL where users will be redirected to authenticate.
CSRF protection token that will be validated in the callback
PKCE code verifier for enhanced security (optional)
The complete authorization URL with all required parameters
exchangeCode
Exchanges the authorization code for access tokens.
Authorization code received from the OAuth callback
PKCE code verifier to validate the authorization request
Promise resolving to OAuth tokens
getUserProfile
Fetches the authenticated user’s profile information.
Access token obtained from the token exchange
Promise resolving to the user’s profile data
OAuthTokens
export interface OAuthTokens {
accessToken: string
refreshToken?: string
expiresIn?: number
tokenType: string
}
The access token for API requests
Optional refresh token for obtaining new access tokens
Token expiration time in seconds
Token type (typically “Bearer”)
OAuthProfile
export interface OAuthProfile {
id: string
email?: string
phone?: string
name?: string
image?: string
emailVerified?: boolean
}
Provider-specific unique user identifier
URL to user’s profile picture
Whether the email has been verified by the provider
Implementation Example
Here’s how to implement a custom OAuth provider:
import type { OAuthProvider, OAuthTokens, OAuthProfile } from "@arraf-auth/core"
import { buildAuthorizationUrl, exchangeCodeForTokens } from "@arraf-auth/core"
export interface CustomProviderConfig {
clientId: string
clientSecret: string
redirectUri: string
scopes?: string[]
}
export function customProvider(config: CustomProviderConfig): OAuthProvider {
const scopes = config.scopes ?? ["openid", "email", "profile"]
return {
id: "custom",
name: "Custom Provider",
clientId: config.clientId,
clientSecret: config.clientSecret,
scopes,
getAuthorizationUrl(state: string, codeVerifier?: string) {
return buildAuthorizationUrl(
"https://provider.com/oauth/authorize",
{
client_id: config.clientId,
redirect_uri: config.redirectUri,
response_type: "code",
scope: scopes.join(" "),
state,
}
)
},
async exchangeCode(code: string, codeVerifier?: string) {
const response = await exchangeCodeForTokens(
"https://provider.com/oauth/token",
{
code,
client_id: config.clientId,
client_secret: config.clientSecret,
redirect_uri: config.redirectUri,
grant_type: "authorization_code",
}
)
if (!response.ok) {
throw new Error("Token exchange failed")
}
const tokens = await response.json()
return {
accessToken: tokens.access_token,
refreshToken: tokens.refresh_token,
expiresIn: tokens.expires_in,
tokenType: tokens.token_type,
} satisfies OAuthTokens
},
async getUserProfile(accessToken: string) {
const response = await fetch("https://provider.com/api/user", {
headers: { Authorization: `Bearer ${accessToken}` },
})
if (!response.ok) {
throw new Error("Failed to fetch user profile")
}
const profile = await response.json()
return {
id: profile.id,
email: profile.email,
name: profile.name,
image: profile.avatar,
emailVerified: profile.email_verified,
} satisfies OAuthProfile
},
}
}
Usage
Add your custom provider to the Arraf Auth configuration:
import { ArrafAuth } from "@arraf-auth/core"
import { customProvider } from "./providers/custom"
const auth = new ArrafAuth({
secret: process.env.AUTH_SECRET,
database: adapter,
providers: [
customProvider({
clientId: process.env.CUSTOM_CLIENT_ID!,
clientSecret: process.env.CUSTOM_CLIENT_SECRET!,
redirectUri: "https://yourdomain.com/api/auth/callback/custom",
}),
],
})
Use the helper functions buildAuthorizationUrl and exchangeCodeForTokens from @arraf-auth/core to simplify OAuth implementation.