Rayfin

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;
}
FieldDescription
userThe signed-in user, or null when no user is signed in.
isAuthenticatedtrue when a valid authenticated session is installed.
isAnonymoustrue for an anonymous or signed-out session.
roleThe user's role when known.
expiresAtWhen 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.

src/auth/checkSession.ts
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.

src/auth/currentSession.ts
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.

src/auth/subscribe.ts
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.

MethodDescription
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.

src/auth/refresh.ts
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.

src/auth/signOut.ts
await client.auth.signOut();

signOutAll() revokes every active session for the current user across devices and returns { count }.

src/auth/signOutAll.ts
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):

EventFires when
AUTH_LOGINA session is established.
AUTH_LOGOUTThe user signs out.
AUTH_REFRESHThe session refreshes.
AUTH_SESSION_EXPIREDThe access token expires and no refresh token can recover the session.
src/auth/expired.ts
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.

scripts/authCleanup.ts
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();
}
PromptGate a page behind authentication
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.
Something wrong on this page?Report an issueEdit this page

On this page