or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

adc.mdcrypto.mdexternal-identity.mdindex.mdoauth2.mdservice-accounts.mdtoken-management.md
tile.json

oauth2.mddocs/

OAuth2 Authentication

OAuth2 client for implementing authorization code flows, managing user tokens, and verifying ID tokens. This is essential for applications that require user consent and authentication.

Capabilities

OAuth2Client Class

Main OAuth2 client for user authentication flows.

/**
 * OAuth2 client for user authorization and token management
 */
class OAuth2Client extends AuthClient {
  constructor(clientId?: string, clientSecret?: string, redirectUrl?: string);
  constructor(options?: OAuth2ClientOptions);
  
  /** Generate authorization URL for OAuth2 flow */
  generateAuthUrl(opts: GenerateAuthUrlOpts): string;
  
  /** Exchange authorization code for tokens */
  getToken(code: string): Promise<GetTokenResponse>;
  getToken(code: string, callback: GetTokenCallback): void;
  
  /** Set OAuth2 credentials */
  setCredentials(credentials: Credentials): void;
  
  /** Get current credentials */
  getCredentials(): Credentials;
  
  /** Refresh access token using refresh token */
  refreshAccessToken(): Promise<RefreshAccessTokenResponse>;
  
  /** Verify ID token and return payload */
  verifyIdToken(options: VerifyIdTokenOptions): Promise<LoginTicket>;
  
  /** Get access token, refreshing if necessary */
  getAccessToken(): Promise<{ token?: string | null; res?: GaxiosResponse }>;
  
  /** Get ID token for target audience */
  getIdToken(targetAudience: string): Promise<string>;
  
  /** Get Google's federated signon certificates */
  getFederatedSignonCerts(): Promise<{ [keyId: string]: string }>;
  
  /** Get token information from Google */
  getTokenInfo(accessToken: string): Promise<TokenInfo>;
  
  /** Revoke tokens */
  revokeToken(token: string): Promise<RevokeTokenResponse>;
  
  /** Generate code verifier and challenge for PKCE (async) */
  generateCodeVerifierAsync(): Promise<CodeVerifierResults>;
  
  /** Get token information from Google */
  getTokenInfo(accessToken: string): Promise<TokenInfo>;
  
  /** Revoke tokens */
  revokeCredentials(): Promise<RevokeCredentialsResult>;
  revokeCredentials(callback: (err?: Error, result?: RevokeCredentialsResult) => void): void;
  
  /** Get Google's federated signon certificates */
  getFederatedSignonCerts(): Promise<FederatedSignonCertsResponse>;
  getFederatedSignonCerts(callback: GetFederatedSignonCertsCallback): void;
}

interface OAuth2ClientOptions {
  clientId?: string;
  clientSecret?: string;
  redirectUri?: string;
  eagerRefreshThresholdMillis?: number;
  forceRefreshOnFailure?: boolean;
}

interface GenerateAuthUrlOpts {
  /** OAuth2 access type ('online' or 'offline') */
  access_type?: 'online' | 'offline';
  /** OAuth2 scopes to request */
  scope?: string | string[];
  /** OAuth2 response type */
  response_type?: string;
  /** Optional state parameter */
  state?: string;
  /** PKCE code challenge method */
  code_challenge_method?: CodeChallengeMethod;
  /** PKCE code challenge */
  code_challenge?: string;
  /** Consent prompt behavior */
  prompt?: 'none' | 'consent' | 'select_account';
  /** Include granted scopes */
  include_granted_scopes?: boolean;
  /** Login hint */
  login_hint?: string;
  /** Hosted domain */
  hd?: string;
}

interface GetTokenResponse {
  tokens: Credentials;
  res: GaxiosResponse | null;
}

interface RefreshAccessTokenResponse {
  credentials: Credentials;
  res: GaxiosResponse | null;
}

interface VerifyIdTokenOptions {
  idToken: string;
  audience?: string | string[];
  maxExpiry?: number;
  clockSkew?: number;
}

interface TokenInfo {
  /** Application that is the intended user of the access token */
  aud: string;
  /** Unique identifier for the logged-in user across Google APIs */
  user_id?: string;
  /** Array of scopes that the user granted access to */
  scopes: string[];
  /** Datetime when the token becomes invalid */
  expiry_date: number;
  /** Subject - unique user identifier (same as user_id but standard claim) */
  sub?: string;
  /** Authorized presenter client_id */
  azp?: string;
  /** Access type (online/offline) */
  access_type?: string;
}

interface RevokeCredentialsResult {
  /** Whether revocation was successful */
  success: boolean;
}

interface FederatedSignonCertsResponse {
  /** Certificate data */
  certs: Certificates;
  /** Certificate format (PEM or JWK) */
  format: CertificateFormat;
  /** HTTP response */
  res?: GaxiosResponse<void> | null;
}

interface Certificates {
  [keyId: string]: string | JwkCertificate;
}

enum CertificateFormat {
  PEM = 'PEM',
  JWK = 'JWK'
}

type GetFederatedSignonCertsCallback = (
  err: GaxiosError | null,
  certs?: FederatedSignonCertsResponse,
  response?: GaxiosResponse<void> | null
) => void;

enum CodeChallengeMethod {
  Plain = 'plain',
  S256 = 'S256'
}

interface CodeVerifierResults {
  codeVerifier: string;
  codeChallenge: string;
}

type GetTokenCallback = (err: Error | null, tokens?: Credentials | null, response?: GaxiosResponse | null) => void;

Usage Examples:

import { OAuth2Client } from "google-auth-library";

// Initialize OAuth2 client
const oauth2Client = new OAuth2Client({
  clientId: 'your-client-id.googleusercontent.com',
  clientSecret: 'your-client-secret',
  redirectUri: 'http://localhost:3000/callback'
});

// Generate authorization URL
const authUrl = oauth2Client.generateAuthUrl({
  access_type: 'offline',
  scope: [
    'https://www.googleapis.com/auth/userinfo.profile',
    'https://www.googleapis.com/auth/userinfo.email'
  ],
  prompt: 'consent'
});

console.log('Visit this URL:', authUrl);

// Exchange authorization code for tokens
const { tokens } = await oauth2Client.getToken(authorizationCode);
oauth2Client.setCredentials(tokens);

// Use the client to make authenticated requests
const userInfo = await oauth2Client.request({
  url: 'https://www.googleapis.com/oauth2/v1/userinfo'
});

// Verify ID token
const ticket = await oauth2Client.verifyIdToken({
  idToken: tokens.id_token,
  audience: 'your-client-id.googleusercontent.com'
});

const payload = ticket.getPayload();
console.log('User ID:', payload.sub);
console.log('Email:', payload.email);

PKCE Support

OAuth2Client supports Proof Key for Code Exchange (PKCE) for enhanced security:

import { OAuth2Client } from "google-auth-library";

const oauth2Client = new OAuth2Client(/* ... */);

// Generate code verifier and challenge
const { codeVerifier, codeChallenge } = await oauth2Client.generateCodeVerifierAsync();

// Generate auth URL with PKCE
const authUrl = oauth2Client.generateAuthUrl({
  access_type: 'offline',
  scope: ['https://www.googleapis.com/auth/userinfo.profile'],
  code_challenge_method: 'S256',
  code_challenge: codeChallenge
});

// Exchange code with verifier
const { tokens } = await oauth2Client.getToken(authorizationCode);

Login Ticket

Represents a verified ID token with payload information:

/**
 * Represents a verified Google ID token
 * Contains both the envelope and payload from ID token verification
 */
class LoginTicket {
  constructor(envelope?: string, payload?: TokenPayload);
  
  /** Get the token envelope */
  getEnvelope(): string | undefined;
  
  /** Get the verified token payload */
  getPayload(): TokenPayload | undefined;
  
  /** Get user ID from token (sub claim) */
  getUserId(): string | null;
  
  /** Get both envelope and payload attributes */
  getAttributes(): { envelope?: string; payload?: TokenPayload };
}

interface TokenPayload {
  /** Issuer (always https://accounts.google.com or accounts.google.com) */
  iss: string;
  /** Subject (user ID) - unique identifier, never reused */
  sub: string;
  /** Audience - must be one of your OAuth 2.0 client IDs */
  aud: string;
  /** Issued at time (Unix timestamp) */
  iat: number;
  /** Expiry time (Unix timestamp) */
  exp: number;
  /** Authorized party - client_id of requesting party */
  azp?: string;
  /** Email address (only if email scope requested) */
  email?: string;
  /** Email verified status */
  email_verified?: boolean;
  /** Access token hash for validation */
  at_hash?: string;
  /** Nonce value for replay attack protection */
  nonce?: string;
  /** Full name (only if profile scope requested) */
  name?: string;
  /** Profile picture URL (only if profile scope requested) */
  picture?: string;
  /** Profile page URL (only if profile scope requested) */
  profile?: string;
  /** Given/first name (only if profile scope requested) */
  given_name?: string;
  /** Family/last name (only if profile scope requested) */
  family_name?: string;
  /** Hosted G Suite domain (only if user belongs to hosted domain) */
  hd?: string;
  /** User's locale (BCP 47 language tag) */
  locale?: string;
}

Token Management

interface Credentials {
  /** OAuth2 access token */
  access_token?: string | null;
  /** OAuth2 refresh token */
  refresh_token?: string | null;
  /** Token scope */
  scope?: string;
  /** Token type (usually 'Bearer') */
  token_type?: string;
  /** OpenID Connect ID token */
  id_token?: string | null;
  /** Token expiry timestamp (milliseconds) */
  expiry_date?: number | null;
}

interface RefreshOptions {
  eagerRefreshThresholdMillis?: number;
  forceRefreshOnFailure?: boolean;
}

Error Handling

Common OAuth2 errors:

  • invalid_grant: Authorization code or refresh token is invalid
  • invalid_client: Client credentials are invalid
  • invalid_request: Malformed request parameters
  • access_denied: User denied authorization
try {
  const { tokens } = await oauth2Client.getToken(code);
} catch (error) {
  if (error.response?.data?.error === 'invalid_grant') {
    console.error('Authorization code expired or invalid');
  }
}