OAuth Client for TypeScript: Integrating Authorization in Web Applications

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

OAuth Client for TypeScript: Complete Guide to Implementing Authorization

In modern web development, secure user authentication is one of the key tasks. OAuth 2.0 is an open authorization protocol that allows applications to obtain limited access to user resources without transmitting login and password. In this article, we will walk through how to create an OAuth client in TypeScript that can be used in any web application. The library is suitable for integration with Google, GitHub, Facebook, and other providers.



What is an OAuth Client in TypeScript?

An OAuth client is a set of functions and classes that implement the authorization flow (Authorization Code Flow) on the client or server side. In TypeScript, such a client provides strict typing, which reduces the number of errors and simplifies code maintenance. The main tasks of the client are:

  • Generating a URL to redirect the user to the provider's page.
  • Exchanging a temporary code for an access token and refresh token.
  • Storing and refreshing tokens.
  • Validating request parameters (state, nonce).


Library Architecture

The library consists of several modules:

  • OAuthClient — the main class that manages all stages.
  • TokenStore — an interface for storing tokens (can be implemented in memory, localStorage, or a database).
  • ProviderConfig — configuration for a specific provider (clientId, redirectUri, endpoints).
  • AuthError — a class for handling authorization errors.


Example Implementation in TypeScript

Below is a basic example of an OAuth client for TypeScript. First, let's define the types and interfaces:

// types.tsexport interface TokenResponse {    access_token: string;    token_type: string;    expires_in: number;    refresh_token?: string;    scope?: string;}

export interface ProviderConfig { authorizationEndpoint: string; tokenEndpoint: string; clientId: string; redirectUri: string; scope: string;}

export interface TokenStore { getToken(): Promise<string | null>; setToken(token: TokenResponse): Promise<void>; clearToken(): Promise<void>;}


Now let's create the main OAuthClient class:

// OAuthClient.tsimport { TokenResponse, ProviderConfig, TokenStore } from './types';import { AuthError } from './AuthError';

export class OAuthClient { private config: ProviderConfig; private store: TokenStore;

constructor(config: ProviderConfig, store: TokenStore) { this.config = config; this.store = store; }

// Generate authorization URL getAuthorizationUrl(state: string): string { const params = new URLSearchParams({ client_id: this.config.clientId, redirect_uri: this.config.redirectUri, response_type: 'code', scope: this.config.scope, state: state, }); return `${this.config.authorizationEndpoint}?${params.toString()}`; }

// Exchange code for token async exchangeCodeForToken(code: string, state: string, expectedState: string): Promise<TokenResponse> { if (state !== expectedState) { throw new AuthError('State mismatch. Possible CSRF attack.'); }

const body = new URLSearchParams({ grant_type: 'authorization_code', code: code, redirect_uri: this.config.redirectUri, client_id: this.config.clientId, });

const response = await fetch(this.config.tokenEndpoint, { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: body, });

if (!response.ok)

Recommendations