Skip to content

Silent Authentication

Silent Authentication uses the Authorization Code Flow with prompt=none to check if a user has an active session at the authorization server without displaying any UI. This is useful for:

  • Session restoration — Check if the user is still logged in on page load
  • Token renewal alternative — Obtain fresh tokens when refresh tokens are unavailable
  • Single Sign-On (SSO) — Detect existing sessions across applications
sequenceDiagram
    participant App
    participant SDK
    participant AS as Auth Server

    App->>SDK: Check session
    SDK->>AS: prompt=none
    Note over AS: Session active?
    AS->>SDK: code (or error)
    SDK->>AS: Exchange code
    AS->>SDK: Tokens
    SDK->>App: Result

When prompt=none is set, the authorization server either:

  • Returns an authorization code (if the user has an active session)
  • Returns an error like login_required (if no active session exists)

No login UI is shown to the user in either case.

import { SilentAuthHandler } from '@authrim/core';
const silentAuth = new SilentAuthHandler(config, stateManager, pkceHelper);
const { url } = silentAuth.buildSilentAuthUrl({
redirectUri: 'https://myapp.com/silent-callback',
scope: 'openid profile',
});
ParameterTypeDefaultDescription
redirectUristringRequiredCallback URL for the silent auth response
scopestring'openid'Space-separated scopes
responseType'code' | 'none''code'Response type
loginHintstringHint for which user to check
idTokenHintstringPreviously issued ID token
extraParamsRecord<string, string>Additional parameters
exposeStatebooleanfalseReturn state/nonce in the result

Parse the response URL to determine whether the session is active:

const result = silentAuth.parseSilentAuthResponse(responseUrl);
if (result.success) {
// User has an active session — exchange the code for tokens
const tokens = await authCodeFlow.exchangeCode(discovery, {
code: result.code,
redirectUri: 'https://myapp.com/silent-callback',
codeVerifier: storedCodeVerifier,
});
console.log('Session restored:', tokens);
} else {
// No active session
console.log('No session:', result.error.code);
}
if (!result.success) {
if (silentAuth.isInteractiveLoginRequired(result.error)) {
// User needs to log in interactively
redirectToLogin();
} else {
// Other error (network, server error, etc.)
handleError(result.error);
}
}
Error CodeDescriptionAction
login_requiredNo active session at the authorization serverRedirect to interactive login
interaction_requiredUser interaction is required (e.g., consent)Redirect to interactive login
consent_requiredUser needs to grant consentRedirect to interactive login with prompt=consent
account_selection_requiredMultiple accounts; user must chooseRedirect with prompt=select_account

All of these errors indicate the user cannot be silently authenticated and needs to go through the interactive login flow.

async function restoreSession() {
// First, check if we have valid tokens in storage
const isAuthenticated = await client.session.isAuthenticated();
if (isAuthenticated) {
return; // Already authenticated
}
// Try silent auth to restore from server session
try {
const { url } = silentAuth.buildSilentAuthUrl({
redirectUri: 'https://myapp.com/silent-callback',
});
// Use a hidden iframe to perform silent auth
const responseUrl = await performSilentAuthInIframe(url);
const result = silentAuth.parseSilentAuthResponse(responseUrl);
if (result.success) {
// Exchange code for tokens
const tokens = await exchangeCode(result.code);
console.log('Session restored');
} else if (silentAuth.isInteractiveLoginRequired(result.error)) {
console.log('No active session — user needs to log in');
}
} catch (error) {
console.error('Silent auth failed:', error);
}
}

Pass the previously issued ID token to help the authorization server identify the user:

const idToken = await client.token.getIdToken();
const { url } = silentAuth.buildSilentAuthUrl({
redirectUri: 'https://myapp.com/silent-callback',
idTokenHint: idToken ?? undefined,
});