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
| Name | Type | Required | Description |
|---|---|---|---|
refreshToken | string | yes | The refresh token to exchange |
scopes | string[] | no | Request 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 secondsAutomatic 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
| Name | Type | Required | Description |
|---|---|---|---|
token | string | yes | The token to revoke (access or refresh) |
tokenTypeHint | "access_token" | "refresh_token" | no | Hint 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
| Name | Type | Required | Description |
|---|---|---|---|
token | string | yes | The token to introspect |
tokenTypeHint | "access_token" | "refresh_token" | no | Hint 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): IdTokenClaimsReturns
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 class | HTTP status | When |
|---|---|---|
InvalidGrantError | 400 | Refresh token expired or revoked |
InvalidClientError | 401 | Client authentication failed (introspect) |
RateLimitError | 429 | Too many requests |
See also
- Authorization URL -- Build authorization URLs
- Code exchange -- Exchange codes for tokens
- Client credentials -- M2M token acquisition
- OAuth types -- TokenSet and related types