Sessions
Use Rayfin's opaque auth session safely: read documented fields, subscribe with onSessionChange, refresh, and sign out.
Every supported Rayfin sign-in path installs the same opaque session on client.auth.
Fabric SSO popup, Fabric embedded auth, direct Entra token sign-in, and external embed host differ in how the session is acquired, not in how your app reads it.
Sessions are opaque
client.auth.getSession() returns an OpaqueSession synchronously.
Treat it as opaque: read the fields below, but do not infer meaning from internal fields or storage shape.
Raw Rayfin access and refresh tokens are intentionally hidden.
interface OpaqueSession {
user: User | null;
role?: string;
expiresAt?: Date;
isAuthenticated: boolean;
isAnonymous: boolean;
}| Field | Description |
|---|---|
user | The signed-in user, or null when no user is signed in. |
isAuthenticated | true when a valid authenticated session is installed. |
isAnonymous | true for an anonymous or signed-out session. |
role | The user's role when known. |
expiresAt | When the current Rayfin access token expires. |
Warning
Gate UI logic on isAuthenticated or the presence of user.
Do not depend on session internals. Rayfin can change those without breaking apps that use only the documented fields.
const session = client.auth.getSession();
if (session.isAuthenticated && session.user) {
showApp(session.user);
} else {
showSignInPage();
}Read the current session once
getSession() reflects whatever Rayfin currently has in memory.
Call it once on startup, then rely on onSessionChange for updates.
const session = client.auth.getSession();
console.log('Authenticated:', session.isAuthenticated);Subscribe with onSessionChange
onSessionChange fires after sign-in, sign-out, token refresh, user updates, and expiration.
It returns an unsubscribe function.
const unsubscribe = client.auth.onSessionChange((session) => {
if (session?.isAuthenticated) {
console.log('Signed in as', session.user?.email);
} else {
console.log('Signed out');
}
});
// Later, for example on component unmount:
unsubscribe();Warning
The method is onSessionChange.
onAuthStateChange does not exist on the Rayfin auth client.
See React integration for a complete AuthProvider and useAuth() hook.
Let Rayfin handle tokens
Rayfin attaches the current session to client.data.* and client.functions.* calls.
Application code should not read, store, or forward Rayfin tokens.
| Method | Description |
|---|---|
hasRefreshToken() | Returns whether a Rayfin refresh token is available. |
refreshSession() | Refreshes the current session using the stored Rayfin refresh token. Concurrent calls share one in-flight request. |
startAutoRefresh() | Re-enables scheduled refresh when autoRefreshToken: false was used. |
stopAutoRefresh() | Cancels scheduled refresh when autoRefreshToken: false was used. |
destroy() | Removes listeners and timers. Use it when a standalone Auth instance is no longer needed. |
refreshSession() exists to satisfy the refresh contract, not as a supported way to extract a token for reuse elsewhere.
A Node.js script that constructs Auth with storage: false does not have a stored browser refresh token until a provider installs a session.
See Seeding data for what a script can authenticate as.
Rayfin schedules a refresh automatically as the access token approaches expiry when a refresh token is available.
Most browser apps do not need to call refreshSession() directly.
if (client.auth.hasRefreshToken()) {
try {
await client.auth.refreshSession();
} catch {
await client.auth.signOut();
}
}Direct Entra token sign-in stores a Rayfin session, not the supplied Entra token. Later refreshes use the Rayfin refresh token. If refresh can no longer establish a Rayfin session, acquire another delegated Entra token and sign in again.
Sign out
signOut() revokes the current access token and clears the local session.
await client.auth.signOut();signOutAll() revokes every active session for the current user across devices and returns { count }.
const result = await client.auth.signOutAll();
console.log(`Revoked ${result.count} sessions`);Auth events
Use onSessionChange for most UI.
For narrower lifecycle handling, subscribe to a named event with on(event, handler):
| Event | Fires when |
|---|---|
AUTH_LOGIN | A session is established. |
AUTH_LOGOUT | The user signs out. |
AUTH_REFRESH | The session refreshes. |
AUTH_SESSION_EXPIRED | The access token expires and no refresh token can recover the session. |
const unsubscribe = client.auth.on('AUTH_SESSION_EXPIRED', () => {
redirectToSignIn();
});
unsubscribe();Server or script cleanup
When you construct Auth directly for Node.js or a short-lived server operation, use memory-only storage and call destroy() in finally.
Use a separate Auth instance per user session in server code.
import { Auth } from '@microsoft/rayfin-auth';
import { ApiClient } from '@microsoft/rayfin-lib';
const apiClient = new ApiClient({
baseUrl: process.env.RAYFIN_API_URL!,
publishableKey: process.env.RAYFIN_PUBLISHABLE_KEY!,
});
const auth = new Auth(apiClient, { storage: false });
auth.attachToClient(apiClient);
try {
await runWork(auth);
} finally {
auth.destroy();
}In my Rayfin React app, gate the main app route behind authentication.
On mount, read client.auth.getSession() once, then subscribe with client.auth.onSessionChange(...) to keep it in sync. Do not use onAuthStateChange; it does not exist on the Rayfin auth client.
Show a loading state until the first session check completes, then render the app if session.isAuthenticated and session.user are present, or redirect to a sign-in page otherwise. Do not introspect any session fields beyond isAuthenticated, isAnonymous, user, role, and expiresAt.