> For the complete documentation index, see [llms.txt](https://docs.oidc-spa.dev/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.oidc-spa.dev/resources/jwt-of-the-access-token.md).

# JWT Of the Access Token

And why it's not supposed to be read on the client side.

You might be surprised, or even frustrated, that oidc-spa only provides the decoded ID token and not the decoded access token. This is intentional: the access token is meant to be **opaque** to the client application. It should be used only as an authentication key (e.g., a Bearer token when calling an API). According to the OAuth 2.0 specification, [the access token is not even required to be a JWT](https://datatracker.ietf.org/doc/html/rfc6749#section-1.4):

> The string is usually opaque to the client. \[...] The token may denote an identifier used to retrieve the authorization information or may self-contain the authorization information in a verifiable manner (i.e., a token string consisting of some data and a signature).

The good news is that everything you need is usually found in the ID token. If you notice that certain information appears in the access token but not in the ID token, there are two likely reasons:

1. **Identity server policy** – Your identity provider may have an explicit rule stripping or not including those claims in the ID token. For example, [Keycloak does not include](https://github.com/keycloak/keycloak/issues/14617#issuecomment-1268412474) the `realm_access` claim in the ID token by default.
2. **Schema filtering** – [When using `decodedIdTokenSchema` with Zod](https://docs.oidc-spa.dev/integration-guides/usage#basic-usage), any claims not declared in your schema will be discarded. This can make it seem like the ID token contains fewer claims than it actually does. To see the complete payload, initialize the adapter with `debugLogs: true`, disable `decodedIdTokenSchema`, and check your browser console output.

## Manually decoding the access token

If you absolutely need to introspect the access token, such as when migrating from another library and you cannot modify the IDP's configuration, you can decode it manually using:

{% tabs %}
{% tab title="Vanilla API" %}

```typescript
import { decodeJwt } from 'oidc-spa/decode-jwt';

const decodedAccessToken = decodeJwt(await oidc.getAccessToken());
```

{% endtab %}

{% tab title="React" %}
{% code title="src/oidc.ts" %}

```typescript
import { oidcSpa } from "oidc-spa/react-spa";
import { decodeJwt } from "oidc-spa/decode-jwt";

export const {
    bootstrapOidc,
    getOidc,
    // ...
} = oidcSpa
    .withExpectedDecodedIdTokenShape({ /* ... */ })
    .createUtils();

let decodedAccessToken: Record<string, unknown> | undefined;

getOidc().then(async oidc => {
    if (!oidc.isUserLoggedIn) {
        return;
    }

    const accessToken = await oidc.getAccessToken();

    decodedAccessToken = decodeJwt(accessToken);

    // Using Zod to validate the shape is recommended as well:
    // decodedAccessToken = DecodedAccessTokenSchema.parse(decodeJwt(accessToken));
});

export function getDecodedAccessToken(): Record<string, unknown> | undefined {
    if (decodedAccessToken === undefined) {
        throw new Error("Decoded access token accessed too early. Only use in a component inside <OidcInitializationGate />.");
    }

    return decodedAccessToken;
}
```

{% endcode %}
{% endtab %}
{% endtabs %}


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.oidc-spa.dev/resources/jwt-of-the-access-token.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `build a script that syncs our docs to a CMS` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
