For the complete documentation index, see llms.txt. This page is also available as Markdown.

The User Object

Access the User in Your App

Once configured, your custom user model is available throughout your frontend code.

src/greeting.ts
import { prOidc } from "./oidc";

export async function getGreeting() {
    const oidc = await prOidc;

    if (!oidc.isUserLoggedIn) {
        return "Hello!";
    }

    const { user } = await oidc.getUser();

    return `Hello ${user.displayName}!`;
}

In a component where login is already enforced:

src/components/Greeting.tsx
import { useOidc } from "../oidc";

export function Greeting() {
    const { user } = useOidc({ assert: "user logged in" });

    return <p>Hello {user.displayName}!</p>;
}

In browser code outside a React component:

src/greeting.ts
import { getOidc } from "./oidc";

export async function getGreeting() {
    const oidc = await getOidc({ assert: "user logged in" });
    const { user } = await oidc.getUser();

    return `Hello ${user.displayName}!`;
}

The user abstraction is not available in the Angular adapter yet.

The user object is your application's model of the signed-in person. Shape it around what the frontend needs to render.

Implement createUser

Keep src/oidc.user.ts focused on translating identity data into the model consumed by your UI:

  1. Define a User type containing exactly the information your UI needs.

  2. Implement createUser to gather that information and return a User.

Here are some example of the sources you can use to construct the user object.

The decoded payload of the ID token is the simplest source when it already contains everything your UI needs.

A dedicated endpoint is often the best option when the model depends on your application's database.

The backend validates the access token, identifies the caller, loads the corresponding record, and returns an application-specific object.

Some providers expose roles or groups only in a JWT access token. This Keycloak-shaped example turns those roles into UI-friendly fields.

fetchUserInfo() calls the standard OIDC UserInfo endpoint discovered from your provider's metadata and attaches the current access token.

No UserInfo request is made unless you call fetchUserInfo(). The available claims still depend on your requested scopes and provider configuration.

Provider-specific APIs can expose information that is not available through standard OIDC claims. For Keycloak, oidc-spa includes a typed helper for the account profile.

The endpoint must be enabled and accessible to your client. Keep this provider-specific code inside createUser so the rest of the UI remains provider-agnostic.

What else is available to createUser?
  • decodedIdToken is the raw decoded ID token payload. Validate the claims your UI depends on, even if you also configured withExpectedDecodedIdTokenShape().

  • accessToken is the current access token. Use it to call a resource server, but do not store it in User because tokens rotate.

  • fetchUserInfo lazily calls the discovered standard UserInfo endpoint.

  • issuerUri lets you select provider-specific behavior.

  • user_current is undefined on the first build and contains the previous model during subsequent rebuilds.

createUser may return a User directly or a promise. Do not call getUser() directly or indirectly from inside it: getUser() is already waiting for createUser() to finish.

Connect It to Your Adapter

createUser is framework-independent. Register it when configuring oidc-spa. If your project supports mock mode, register user_mock alongside it.

When bootstrapOidc() receives { implementation: "mock", ... }, it uses this user_mock by default. You can override it by passing a different user_mock to that bootstrap call.

When bootstrapOidc() receives { implementation: "mock", ... }, it uses this user_mock by default. You can override it by passing a different user_mock to that bootstrap call.

In TanStack Start, frontend components and the resource server share a project, but they do not share a trust boundary.

The app-level user is created in the browser for UI concerns. On the backend, server functions and API handlers identify and authorize the caller from the validated oidc.accessTokenClaims supplied by oidcFnMiddleware or oidcRequestMiddleware. See TanStack Start example repo.

Angular support is not implemented yet, so there is currently no createUser registration API.

Keep the User Up to Date

oidc-spa runs createUser when it first builds the signed-in user's model. It runs createUser again when it detects meaningful changes in the decoded ID token or the decoded payload of a JWT access token. Routine rotation-only changes, such as new iat or exp values, do not rebuild the user.

When createUser reads from an external source, such as your API, UserInfo, or a provider-specific profile endpoint, oidc-spa cannot detect changes to that source. After an update succeeds, call refreshUser() to rebuild the user.

With the real implementation, refreshUser() renews the tokens, forces createUser to run again, notifies user subscribers, and resolves to the refreshed User. In mock mode, it simply resolves to the configured user_mock.

Call refreshCurrentUser() after the external update has completed.

Components that read user through useOidc() re-render with the refreshed value.

The user abstraction is not available in the Angular adapter yet.

Last updated

Was this helpful?