OpenID Connect (OIDC) & OAuth2 client library for TypeScript/JavaScript applications
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
User profile and token data structures with comprehensive claims support and token lifecycle management for authenticated users.
Represents an authenticated user with profile information and tokens.
/**
* Represents an authenticated user with profile and token information
*/
class User {
constructor(args: {
id_token?: string;
session_state?: string | null;
access_token: string;
refresh_token?: string;
token_type: string;
scope?: string;
profile: UserProfile;
expires_at?: number;
userState?: unknown;
url_state?: string;
});
/** The raw ID token */
readonly id_token?: string;
/** Session state for session management */
readonly session_state: string | null;
/** The access token for API calls */
readonly access_token: string;
/** The refresh token for token renewal */
readonly refresh_token?: string;
/** Token type (usually "Bearer") */
readonly token_type: string;
/** Space-delimited scope values */
readonly scope?: string;
/** User profile extracted from ID token */
readonly profile: UserProfile;
/** Timestamp when access token expires */
readonly expires_at?: number;
/** Custom state data from authentication */
readonly state: unknown;
/** URL state parameter */
readonly url_state?: string;
/** Seconds until access token expires */
readonly expires_in?: number;
/** Whether the access token has expired */
readonly expired?: boolean;
/** Array of individual scope values */
readonly scopes: string[];
/** Serialize user to string for storage */
toStorageString(): string;
/** Create User from storage string */
static fromStorageString(storageString: string): User;
}Standard OIDC user profile with optional claims.
/**
* User profile information from ID token and userinfo endpoint
*/
interface UserProfile extends IdTokenClaims {
/** Subject identifier - unique user ID */
sub: string;
// Standard profile claims
/** Full display name */
name?: string;
/** Given name (first name) */
given_name?: string;
/** Family name (last name) */
family_name?: string;
/** Middle name */
middle_name?: string;
/** Casual name or alias */
nickname?: string;
/** Preferred username for display */
preferred_username?: string;
/** Profile page URL */
profile?: string;
/** Picture/avatar URL */
picture?: string;
/** Website URL */
website?: string;
// Contact claims
/** Email address */
email?: string;
/** Whether email is verified */
email_verified?: boolean;
/** Phone number */
phone_number?: string;
/** Whether phone number is verified */
phone_number_verified?: boolean;
// Personal information
/** Gender */
gender?: string;
/** Date of birth (YYYY-MM-DD format) */
birthdate?: string;
/** Time zone */
zoneinfo?: string;
/** Locale/language preference */
locale?: string;
/** Last profile update timestamp */
updated_at?: number;
/** Postal address information */
address?: OidcAddressClaim;
}
/**
* Standard OIDC address claim structure
*/
interface OidcAddressClaim {
/** Full mailing address */
formatted?: string;
/** Street address */
street_address?: string;
/** City or locality */
locality?: string;
/** State, province, prefecture, or region */
region?: string;
/** ZIP or postal code */
postal_code?: string;
/** Country name */
country?: string;
}JWT claims structure for ID tokens.
/**
* Standard ID token claims from JWT
*/
interface IdTokenClaims extends JwtClaims {
/** Subject identifier */
sub: string;
/** Authentication time */
auth_time?: number;
/** Authentication Context Class Reference */
acr?: string;
/** Authentication Methods References */
amr?: string[];
/** Authorized party */
azp?: string;
/** Access token hash */
at_hash?: string;
/** Code hash */
c_hash?: string;
/** Nonce value */
nonce?: string;
}
/**
* Base JWT claims structure
*/
interface JwtClaims {
/** Issuer */
iss: string;
/** Subject */
sub: string;
/** Audience */
aud: string | string[];
/** Expiration time */
exp: number;
/** Issued at time */
iat: number;
/** Not before time */
nbf?: number;
/** JWT ID */
jti?: string;
/** Additional custom claims */
[key: string]: unknown;
}Complete set of standard OIDC claims.
/**
* Standard OIDC claims as defined in the specification
*/
interface OidcStandardClaims {
/** Subject identifier */
sub: string;
/** Full display name */
name?: string;
/** Given name */
given_name?: string;
/** Family name */
family_name?: string;
/** Middle name */
middle_name?: string;
/** Nickname */
nickname?: string;
/** Preferred username */
preferred_username?: string;
/** Profile page URL */
profile?: string;
/** Picture URL */
picture?: string;
/** Website URL */
website?: string;
/** Email address */
email?: string;
/** Email verified flag */
email_verified?: boolean;
/** Gender */
gender?: string;
/** Date of birth */
birthdate?: string;
/** Time zone */
zoneinfo?: string;
/** Locale */
locale?: string;
/** Phone number */
phone_number?: string;
/** Phone verified flag */
phone_number_verified?: boolean;
/** Address */
address?: OidcAddressClaim;
/** Last update time */
updated_at?: number;
}import { UserManager, User } from "oidc-client-ts";
const userManager = new UserManager({
authority: "https://demo.identityserver.io",
client_id: "interactive.public",
redirect_uri: "http://localhost:3000/callback",
response_type: "code",
scope: "openid profile email phone address",
});
// Get current user
const user = await userManager.getUser();
if (user && !user.expired) {
console.log("User Information:", {
id: user.profile?.sub,
name: user.profile?.name,
email: user.profile?.email,
emailVerified: user.profile?.email_verified,
picture: user.profile?.picture,
});
console.log("Token Information:", {
accessToken: user.access_token,
tokenType: user.token_type,
expiresIn: user.expires_in,
scopes: user.scopes,
hasRefreshToken: !!user.refresh_token,
});
}import { UserManager, User } from "oidc-client-ts";
const userManager = new UserManager({
// ... configuration
automaticSilentRenew: true,
accessTokenExpiringNotificationTimeInSeconds: 60,
});
// Monitor token expiration
userManager.events.addAccessTokenExpiring((user: User) => {
console.log(`Access token expiring in ${user.expires_in} seconds`);
// Could show notification to user
showTokenExpirationWarning();
});
userManager.events.addAccessTokenExpired(() => {
console.log("Access token has expired");
// Redirect to login or attempt silent renewal
handleTokenExpiration();
});
// Check token status
function checkTokenStatus(user: User | null) {
if (!user) {
return "Not authenticated";
}
if (user.expired) {
return "Token expired";
}
if (user.expires_in && user.expires_in < 300) { // 5 minutes
return "Token expiring soon";
}
return "Token valid";
}import { UserManager } from "oidc-client-ts";
const userManager = new UserManager({
authority: "https://your-provider.com",
client_id: "your-client",
redirect_uri: "http://localhost:3000/callback",
response_type: "code",
scope: "openid profile email custom_scope",
// Load additional user info
loadUserInfo: true,
// Keep custom claims
filterProtocolClaims: ["nbf", "jti", "auth_time", "nonce", "acr", "amr", "azp", "at_hash"],
// Merge strategy for claims
mergeClaimsStrategy: { array: "merge" },
});
// Access custom claims
const user = await userManager.getUser();
if (user?.profile) {
// Standard claims
const standardInfo = {
name: user.profile.name,
email: user.profile.email,
picture: user.profile.picture,
};
// Custom claims (assuming your provider includes these)
const customInfo = {
department: (user.profile as any).department,
roles: (user.profile as any).roles,
permissions: (user.profile as any).permissions,
tenant: (user.profile as any).tenant_id,
};
console.log("Standard claims:", standardInfo);
console.log("Custom claims:", customInfo);
}import { User, OidcAddressClaim } from "oidc-client-ts";
function displayUserAddress(user: User) {
const address = user.profile?.address;
if (address) {
console.log("User Address:");
if (address.formatted) {
console.log("Formatted:", address.formatted);
} else {
// Build address from components
const components = [
address.street_address,
address.locality,
address.region,
address.postal_code,
address.country,
].filter(Boolean);
console.log("Address:", components.join(", "));
}
}
}
// Example address claim structure
const exampleAddress: OidcAddressClaim = {
formatted: "123 Main St\nAnytown, CA 12345\nUSA",
street_address: "123 Main St",
locality: "Anytown",
region: "CA",
postal_code: "12345",
country: "USA",
};import { User } from "oidc-client-ts";
// Manual user storage (normally handled by UserManager)
function storeUser(user: User) {
const userString = user.toStorageString();
localStorage.setItem("oidc.user", userString);
}
function loadUser(): User | null {
const userString = localStorage.getItem("oidc.user");
if (userString) {
try {
return User.fromStorageString(userString);
} catch (error) {
console.error("Failed to load user from storage:", error);
localStorage.removeItem("oidc.user");
return null;
}
}
return null;
}
// Usage
const user = await userManager.getUser();
if (user) {
storeUser(user);
}
const storedUser = loadUser();
if (storedUser && !storedUser.expired) {
console.log("Loaded user from storage:", storedUser.profile?.name);
}Install with Tessl CLI
npx tessl i tessl/npm-oidc-client-ts