Skip to Content
Documentation TypeScript SDK

Veslo Auth SDK TypeScript

TypeScript SDK for Veslo OIDC (OpenID Connect) authentication. This library provides a simple and type-safe way to integrate OAuth2/OIDC authentication flows into your TypeScript applications.

Installation

npm install veslo-auth-sdk-ts

Quick Start

import { OAuth2Client } from "veslo-auth-sdk-ts";
 
// Initialize the OAuth2 client
const client = new OAuth2Client({
  clientSecret: "your-client-secret",
  clientId: "your-client-id",
  redirectUri: "http://localhost:3000/callback",
});
 
// Generate authorization URL (now async with PKCE support)
// Returns { url: string, codeVerifier: string | undefined }
const { url: authUrl, codeVerifier } = await client.generateAuthUrl({});
console.log(authUrl);
 
// Store codeVerifier for later use (e.g., in sessionStorage)
if (codeVerifier) {
  sessionStorage.setItem("code_verifier", codeVerifier);
}
 
// After user authorizes, exchange the code for tokens
const code = "authorization-code-from-callback";
const storedCodeVerifier = sessionStorage.getItem("code_verifier");
 
(async () => {
  const { access_token } = await client.getToken({
    code,
    codeVerifier: storedCodeVerifier!,
  });
  console.log(access_token);
 
  // Get user information
  const userInfo = await client.getUserInfo(access_token);
  console.log(userInfo);
})();

API Reference

OAuth2Client

The main class for handling OAuth2/OIDC authentication flows.

Constructor

new OAuth2Client(config: OAuth2ClientConfig)

Parameters:

  • config.clientId (string, required): Your OAuth2 client ID
  • config.clientSecret (string, required): Your OAuth2 client secret
  • config.redirectUri (string, required): The redirect URI registered with your OAuth2 provider

Example:

const client = new OAuth2Client({
  clientId: "oidcCLIENT",
  clientSecret: "wswsws",
  redirectUri: "http://localhost:3000/callback",
});

Methods

generateAuthUrl(options?)

Generates the authorization URL that users will be redirected to for authentication. This method is async and automatically implements PKCE (Proof Key for Code Exchange) for enhanced security.

Parameters:

  • options.access_type (optional): "online" or "offline". Default: "offline".
  • options.scope (optional): String or array of strings representing the OAuth2 scopes. Default: "openid profile email".
  • options.state (optional): A state parameter for CSRF protection.
  • options.prompt (optional): Prompt parameter (e.g., "consent", "none").
  • options.codeChallenge (optional): Pre-generated code challenge. If not provided, a code verifier and challenge will be auto-generated.
  • options.codeChallengeMethod (optional): Code challenge method (e.g., "S256"). Required if codeChallenge is provided.

Returns: Promise<{ url: string; codeVerifier: string | undefined }> - An object containing:

  • url (string): The authorization URL
  • codeVerifier (string | undefined): The code verifier (only returned if auto-generated). Important: Store this securely (e.g., in sessionStorage) as it’s required for token exchange.

Example:

// Basic usage - code verifier is auto-generated
const { url: authUrl, codeVerifier } = await client.generateAuthUrl({});
console.log(authUrl);
 
// Store codeVerifier for later use in token exchange
if (codeVerifier) {
  sessionStorage.setItem("code_verifier", codeVerifier);
}
 
// With custom options
const { url: authUrl, codeVerifier } = await client.generateAuthUrl({
  access_type: "offline",
  scope: ["openid", "profile", "email"],
  state: "random-state-string",
  prompt: "consent",
});
 
// With pre-generated code challenge (codeVerifier will be undefined)
const { url: authUrl } = await client.generateAuthUrl({
  codeChallenge: "your-pre-generated-challenge",
  codeChallengeMethod: "S256",
});
getToken({ code, codeVerifier })

Exchanges an authorization code for an access token. Requires the code verifier for PKCE validation.

Parameters:

  • code (string, required): The authorization code received from the OAuth2 provider after user authorization.
  • codeVerifier (string, required): The code verifier that was generated during generateAuthUrl(). This must match the code challenge sent in the authorization request.

Returns: Promise<TokenResponse> - An object containing:

  • access_token (string): The access token
  • expires_in (number, optional): Token expiration time in seconds
  • token_type (string, optional): Usually "Bearer"
  • id_token (string, optional): OpenID Connect ID token

Example:

const code = "Niq0j2C57UDdKe8FGiYwpFYMbaRQCI2jkgFqO5P68sm";
const codeVerifier = sessionStorage.getItem("code_verifier"); // Retrieved from storage
 
const tokenResponse = await client.getToken({
  code,
  codeVerifier: codeVerifier!,
});
console.log(tokenResponse.access_token);
getUserInfo(accessToken)

Retrieves user information using an access token.

Parameters:

  • accessToken (string, required): The access token obtained from getToken().

Returns: Promise<UserInfo> - An object containing user information:

  • sub (string, optional): Subject identifier
  • email (string, optional): User’s email address
  • name (string, optional): User’s name
  • Additional fields may be present depending on the OAuth2 provider

Example:

const userInfo = await client.getUserInfo(access_token);
console.log(userInfo.email);
console.log(userInfo.name);

Complete OAuth2 Flow Example

Here’s a complete example of the OAuth2 authorization code flow for frontend applications:

React Example

import { OAuth2Client } from "veslo-auth-sdk-ts";
import { useEffect, useState } from "react";
 
// Initialize the client (can be in a separate config file)
const client = new OAuth2Client({
  clientId: "oidcCLIENT",
  clientSecret: "wswsws",
  redirectUri: window.location.origin + "/callback",
});
 
// Login component - redirects user to authorization
function LoginButton() {
  const handleLogin = async () => {
    // Generate authorization URL with state for CSRF protection
    const state = Math.random().toString(36).substring(7);
    sessionStorage.setItem("oauth_state", state);
 
    const { url: authUrl, codeVerifier } = await client.generateAuthUrl({
      access_type: "offline",
      scope: ["openid", "profile", "email"],
      state: state,
    });
 
    // Store codeVerifier for token exchange
    if (codeVerifier) {
      sessionStorage.setItem("code_verifier", codeVerifier);
    }
 
    // Redirect user to authorization page
    window.location.href = authUrl;
  };
 
  return <button onClick={handleLogin}>Login with Veslo</button>;
}
 
// Callback component - handles the OAuth callback
function Callback() {
  const [userInfo, setUserInfo] = useState(null);
  const [error, setError] = useState(null);
 
  useEffect(() => {
    const handleCallback = async () => {
      // Get code and state from URL parameters
      const urlParams = new URLSearchParams(window.location.search);
      const code = urlParams.get("code");
      const state = urlParams.get("state");
      const storedState = sessionStorage.getItem("oauth_state");
 
      // Verify state to prevent CSRF attacks
      if (!state || state !== storedState) {
        setError("Invalid state parameter");
        return;
      }
 
      // Clear stored state
      sessionStorage.removeItem("oauth_state");
 
      if (!code) {
        setError("No authorization code received");
        return;
      }
 
      try {
        // Retrieve code verifier from storage
        const codeVerifier = sessionStorage.getItem("code_verifier");
        if (!codeVerifier) {
          setError("Code verifier not found. Please try logging in again.");
          return;
        }
 
        // Exchange code for access token
        const { access_token } = await client.getToken({
          code,
          codeVerifier,
        });
 
        // Clear code verifier from storage (single use)
        sessionStorage.removeItem("code_verifier");
 
        // Store access token (consider using httpOnly cookies or secure storage)
        localStorage.setItem("access_token", access_token);
 
        // Get user information
        const user = await client.getUserInfo(access_token);
        setUserInfo(user);
 
        // Redirect to home page or dashboard
        window.location.href = "/";
      } catch (err) {
        console.error("Authentication failed:", err);
        setError("Authentication failed. Please try again.");
      }
    };
 
    handleCallback();
  }, []);
 
  if (error) {
    return <div>Error: {error}</div>;
  }
 
  if (userInfo) {
    return <div>Welcome, {userInfo.email}!</div>;
  }
 
  return <div>Authenticating...</div>;
}

Vanilla JavaScript Example

import { OAuth2Client } from "veslo-auth-sdk-ts";
 
// Initialize the client
const client = new OAuth2Client({
  clientId: "oidcCLIENT",
  clientSecret: "wswsws",
  redirectUri: window.location.origin + "/callback.html",
});
 
// Login function - call this when user clicks login button
async function login() {
  // Generate state for CSRF protection
  const state = Math.random().toString(36).substring(7);
  sessionStorage.setItem("oauth_state", state);
 
  // Generate authorization URL (now async, returns { url, codeVerifier })
  const { url: authUrl, codeVerifier } = await client.generateAuthUrl({
    access_type: "offline",
    scope: ["openid", "profile", "email"],
    state: state,
  });
 
  // Store codeVerifier for token exchange
  if (codeVerifier) {
    sessionStorage.setItem("code_verifier", codeVerifier);
  }
 
  // Redirect to authorization page
  window.location.href = authUrl;
}
 
// Callback handler - call this on your callback.html page
async function handleCallback() {
  // Get code and state from URL parameters
  const urlParams = new URLSearchParams(window.location.search);
  const code = urlParams.get("code");
  const state = urlParams.get("state");
  const storedState = sessionStorage.getItem("oauth_state");
 
  // Verify state
  if (!state || state !== storedState) {
    console.error("Invalid state parameter");
    return;
  }
 
  sessionStorage.removeItem("oauth_state");
 
  if (!code) {
    console.error("No authorization code received");
    return;
  }
 
  try {
    // Retrieve code verifier from storage
    const codeVerifier = sessionStorage.getItem("code_verifier");
    if (!codeVerifier) {
      console.error("Code verifier not found");
      return;
    }
 
    // Exchange code for access token
    const { access_token } = await client.getToken({
      code,
      codeVerifier,
    });
 
    // Clear code verifier from storage (single use)
    sessionStorage.removeItem("code_verifier");
 
    // Store access token
    localStorage.setItem("access_token", access_token);
 
    // Get user information
    const userInfo = await client.getUserInfo(access_token);
    console.log("User authenticated:", userInfo);
 
    // Redirect to your app
    window.location.href = "/";
  } catch (error) {
    console.error("Authentication failed:", error);
  }
}
 
// Call handleCallback when callback page loads
if (window.location.pathname === "/callback.html") {
  handleCallback();
}

Type Definitions

OAuth2ClientConfig

interface OAuth2ClientConfig {
  clientId: string;
  clientSecret: string;
  redirectUri: string;
}

TokenResponse

interface TokenResponse {
  access_token: string;
  expires_in?: number;
  token_type?: string;
  id_token?: string;
}

UserInfo

interface UserInfo {
  sub?: string;
  email?: string;
  name?: string;
  [key: string]: any;
}

Error Handling

All methods throw errors when API calls fail. Always wrap calls in try-catch blocks:

try {
  const codeVerifier = sessionStorage.getItem("code_verifier");
  if (!codeVerifier) {
    throw new Error("Code verifier not found");
  }
 
  const tokenResponse = await client.getToken({
    code,
    codeVerifier,
  });
  const userInfo = await client.getUserInfo(tokenResponse.access_token);
} catch (error) {
  console.error("Authentication error:", error.message);
  // Handle error appropriately
}

Features

  • ✅ OAuth2/OIDC Authorization Code Flow
  • ✅ PKCE (Proof Key for Code Exchange) for enhanced security
    • Auto-generates code verifier and challenge if not provided
    • Supports custom code challenge and method
  • ✅ TypeScript support with full type definitions
  • ✅ Works in both browser and Node.js environments (Node.js 18+)

PKCE (Proof Key for Code Exchange)

This SDK automatically implements PKCE for enhanced security. When you call generateAuthUrl():

  • If you don’t provide codeChallenge: The SDK automatically generates a code verifier and its corresponding challenge. The code verifier is returned and must be stored securely (e.g., in sessionStorage) for use during token exchange.

  • If you provide codeChallenge: You must also provide codeChallengeMethod, and you’re responsible for managing the code verifier yourself. The SDK will not return a code verifier in this case.

Important: Always store the code verifier securely (sessionStorage is recommended) and use it when calling getToken(). The code verifier should be cleared after successful token exchange.

Requirements

  • Node.js >= 18.0.0 (for native fetch API and Web Crypto API support)
  • TypeScript >= 5.0.0

License (Proprietary SDK — Use Allowed, No Modifications)

Copyright (c) 2025 Veslo s. r. o. All rights reserved.

Last updated on