Avnology ID
SDKsTypeScript SDKOAuth 2.1

Token Management

Refresh, revoke, and introspect OAuth 2.1 tokens with the TypeScript SDK.

Token Management

After obtaining tokens via code exchange or client credentials, you can refresh access tokens, revoke tokens, and introspect tokens to check their validity.

refreshToken()

Exchange a refresh token for a new token set. The old refresh token is rotated (invalidated) and a new one is returned.

client.oauth.refreshToken(params: RefreshTokenParams): Promise<TokenSet>

Parameters

NameTypeRequiredDescription
refreshTokenstringyesThe refresh token to exchange
scopesstring[]noRequest a subset of the original scopes

Returns

Promise<TokenSet> -- A new token set with fresh access token and rotated refresh token.

Basic usage

const newTokens = await client.oauth.refreshToken({
  refreshToken: "rt_abc123...",
});

console.log(newTokens.accessToken);  // New access token
console.log(newTokens.refreshToken); // New refresh token (rotated)
console.log(newTokens.expiresIn);    // 900 seconds

Automatic refresh

When autoRefresh: true (the default), the SDK automatically refreshes tokens before they expire. You can listen for refresh events.

const client = new AvnologyId({
  baseUrl: "https://api.id.avnology.com",
  clientId: "app_abc123",
  autoRefresh: true,
  onTokenRefresh: (tokens) => {
    // Persist the new tokens
    localStorage.setItem("avnology_tokens", JSON.stringify(tokens));
    console.log("Tokens auto-refreshed. New expiry:", tokens.expiresAt);
  },
});

Downscope on refresh

Request a subset of the originally granted scopes when refreshing. Useful for creating limited-scope tokens for specific operations.

const limitedTokens = await client.oauth.refreshToken({
  refreshToken: "rt_abc123...",
  scopes: ["openid", "profile"],  // Only profile access, not email
});

revokeToken()

Revoke an access token or refresh token. Revoking a refresh token also invalidates all access tokens derived from it.

client.oauth.revokeToken(params: RevokeTokenParams): Promise<void>

Parameters

NameTypeRequiredDescription
tokenstringyesThe token to revoke (access or refresh)
tokenTypeHint"access_token" | "refresh_token"noHint for faster processing

Basic usage

// Revoke the refresh token (also invalidates derived access tokens)
await client.oauth.revokeToken({
  token: "rt_abc123...",
  tokenTypeHint: "refresh_token",
});

// Revoke a specific access token
await client.oauth.revokeToken({
  token: "eyJhbGciOi...",
  tokenTypeHint: "access_token",
});

Revoke on logout

async function logout() {
  const tokens = client.getTokens();
  if (tokens?.refreshToken) {
    await client.oauth.revokeToken({
      token: tokens.refreshToken,
      tokenTypeHint: "refresh_token",
    });
  }
  client.clearTokens();
  redirectToLogin();
}

introspectToken()

Check whether a token is active and retrieve its claims. Typically used by resource servers to validate access tokens.

client.oauth.introspectToken(params: IntrospectTokenParams): Promise<TokenIntrospection>

Parameters

NameTypeRequiredDescription
tokenstringyesThe token to introspect
tokenTypeHint"access_token" | "refresh_token"noHint for faster processing

Returns

interface TokenIntrospection {
  active: boolean;         // Whether the token is valid
  sub: string;             // Subject (user ID)
  clientId: string;        // OAuth client ID
  scope: string;           // Granted scopes
  exp: number;             // Expiry (Unix timestamp)
  iat: number;             // Issued at (Unix timestamp)
  iss: string;             // Issuer URL
  aud: string[];           // Audiences
  tokenType: string;       // "Bearer"
  orgId?: string;          // Organization ID (if applicable)
  orgName?: string;        // Organization name
}

Basic usage

const result = await client.oauth.introspectToken({
  token: accessToken,
});

if (result.active) {
  console.log("Token is valid");
  console.log("User:", result.sub);
  console.log("Scopes:", result.scope);
  console.log("Expires:", new Date(result.exp * 1000));
  console.log("Org:", result.orgName);
} else {
  console.log("Token is expired or revoked");
}

Server-side token validation (Express)

import { AvnologyId } from "@avnology/sdk-typescript";

const client = new AvnologyId({
  baseUrl: "https://api.id.avnology.com",
  clientId: "app_abc123",
  clientSecret: "sk_live_...",
});

app.use(async (req, res, next) => {
  const authHeader = req.headers.authorization;
  if (!authHeader?.startsWith("Bearer ")) {
    return res.status(401).json({ error: "Missing bearer token" });
  }

  const token = authHeader.slice(7);
  const result = await client.oauth.introspectToken({ token });

  if (!result.active) {
    return res.status(401).json({ error: "Invalid or expired token" });
  }

  // Attach user info to the request
  req.userId = result.sub;
  req.scopes = result.scope.split(" ");
  req.orgId = result.orgId;
  next();
});

decodeIdToken()

Decode an ID token without verification. For display purposes only -- always verify tokens server-side for security-critical decisions.

client.oauth.decodeIdToken(idToken: string): IdTokenClaims

Returns

interface IdTokenClaims {
  sub: string;          // User ID
  email: string;        // Email address
  email_verified: boolean;
  name: string;         // Full name
  given_name: string;   // First name
  family_name: string;  // Last name
  locale: string;       // Preferred locale
  picture: string;      // Avatar URL
  org_id: string;       // Organization ID
  org_name: string;     // Organization name
  iss: string;          // Issuer
  aud: string;          // Audience (client ID)
  exp: number;          // Expiry timestamp
  iat: number;          // Issued at timestamp
  nonce: string;        // Nonce (if provided)
  at_hash: string;      // Access token hash
}

Common errors

Error classHTTP statusWhen
InvalidGrantError400Refresh token expired or revoked
InvalidClientError401Client authentication failed (introspect)
RateLimitError429Too many requests

See also

On this page