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-tsQuick 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 IDconfig.clientSecret(string, required): Your OAuth2 client secretconfig.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 ifcodeChallengeis provided.
Returns: Promise<{ url: string; codeVerifier: string | undefined }> - An object containing:
url(string): The authorization URLcodeVerifier(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 duringgenerateAuthUrl(). This must match the code challenge sent in the authorization request.
Returns: Promise<TokenResponse> - An object containing:
access_token(string): The access tokenexpires_in(number, optional): Token expiration time in secondstoken_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 fromgetToken().
Returns: Promise<UserInfo> - An object containing user information:
sub(string, optional): Subject identifieremail(string, optional): User’s email addressname(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 providecodeChallengeMethod, 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.