> ## Documentation Index
> Fetch the complete documentation index at: https://docs-dev-update-anonymous-sessons-ea.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Anonymous Sessions

> Learn how to create and manage user sessions without requiring authentication.

export const ReleaseStageNotice = ({feature, stage, plans, contact, terms}) => {
  const stageTextMap = {
    "beta": "Beta",
    "ea": "Early Access"
  };
  const stageText = stageTextMap[stage] || "a product release stage";
  const prsLink = "/docs/troubleshoot/product-lifecycle/product-release-stages";
  const linkify = (text, url) => {
    return <a href={url} target="_blank" rel="noreferrer" class="link">{text}</a>;
  };
  const includeDetails = (plans, contact, terms) => {
    const hasDetails = terms || plans || contact;
    if (!hasDetails) return null;
    return <span data-as="p">
            {plans && <>This feature is available for {linkify(`${plans} plans`, "https://auth0.com/pricing")}. </>}
            {contact && "To participate, contact " + contact + ". "}
            {terms && <>By using this feature, you agree to the applicable Free Trial terms in Okta's {linkify("Master Subscription Agreement", "https://www.okta.com/legal")}.</>}
        </span>;
  };
  return <Warning>
            <span data-as="p">
                <strong>The {feature} feature is in {linkify(stageText, prsLink)}.</strong>
            </span>

            {includeDetails(plans, contact, terms)}
        </Warning>;
};

<ReleaseStageNotice feature="Anonymous Sessions" stage="beta" terms="true" contact="Auth0 Support" />

Anonymous sessions allow you to create and manage [user sessions](/docs/manage-users/sessions) without requiring authentication.

Users can browse, add items to carts or wishlists, complete purchases, and set preferences before creating an account.  Users then bring their activity into their authenticated profile when they sign up or log in.

Use anonymous sessions for the following use cases:

* **Track guest users** across page loads and sessions
* **Store metadata** such as shopping cart references, preferences, consents, and profiling information
* **Issue access tokens** for API calls without requiring authentication
* **Transfer anonymous activity** to authenticated accounts when users sign up or log in

<Warning>
  Auth0 anonymous session Metadata is not a secure data store and should not be used to store sensitive information.
  This includes secrets and high-risk PII like social security numbers or credit card numbers, etc.

  Additionally, the data stored in an anonymous session is not verified for truthness or accuracy and should never be taken at face value.

  Auth0 customers are strongly encouraged to evaluate the data stored in metadata and only store that which is necessary for session tagging and access management purposes.
  To learn more, read [Auth0 General Data Protection Regulation Compliance](/docs/secure/data-privacy-and-compliance/gdpr)."
</Warning>

## How it works

### Gather anonymous sessions data

When you decide to start gathering information about a user, even one who has not authenticated yet, your application sends a `POST` request to the `/anonymous/token` endpoint.

Auth0 responds with two tokens:

* A [**session token**](/docs/secure/tokens/session-tokens) that identifies and persists the anonymous session.
* An [**access token**](/docs/secure/tokens/access-tokens) that the user can present to your [resource servers (APIs)](/docs/get-started/apis).

Subsequent calls that include the session token continue the same session for the same `user_id`, so all activity is traceable to a single origin.
Using the access token, anonymous users can call any of your existing APIs.

```mermaid actions={false} theme={null}
sequenceDiagram
  participant app as SPA/APP
  participant idp as Auth0
  participant rs as Resource Server
  note over app: User Browses the site and <br> we decide to start <br> storing information about them.
  app ->> idp: POST /anonymous/token<br>{language: EN, country: US, order_id: PO123}
  idp ->> app: Session Token, Access Token<br>sub: anon@1234-5678-90
  note over app: User buys something anonymously.
  app ->>+ rs: POST /purchase<br> Authorization: Bearer <Access Token>
  rs ->> rs: Purchase order PO123 created<br>user_id: anon@1234-5678-90
  rs ->>- app: HTTP 200 OK
  note over app: User retrieves their anonymous purchases
  app ->> rs: GET /purchase<br> Authorization: Bearer <Access Token>
  rs ->> app: HTTP 200 OK {purchases: ["PO123"]}
```

```json Anonymous session data of user anon@1234-5678-90 theme={null}
{
  "user_id": "anon@1234-5678-90",
  "session_id": "sess_456",
  "metadata": {
    "language": "EN",
    "country": "US",
    "purchase": "P0123"
  }
}
```

### Transfer anonymous sessions data to user's metadata

There are different mechanisms to transfer an anonymous session into an authenticated user, depending on the flow you are using and where your application resides in terms of domains and FQDNs.

#### Transferring a session in redirect flows (authorization code, authorization code with PKCE)

##### Transferring a session through a cookie

When a user who has an anonymous session decides to log in or sign up, your application passes the `anonymous_session_token` to the `/authorize` endpoint using a cookie. This mechanism works when your application and the authorization server live in the same domain — for example, when your application lives in `application.mydomain.com` and the authorization server's custom domain is `auth.mydomain.com`. In this case, the cookie is considered same-domain and forwarded to the authorization server automatically, so logging in works as usual:

```javascript cookie example theme={null}
// No extra code needed — cookie is sent automatically
await auth0.loginWithRedirect();
```

##### Transferring a session through a transfer ticket

In scenarios where cookies would need to travel cross-domain, multiple browser mechanisms will block the anonymous session cookie from being sent over the network. Even with the correct CORS configuration on the server and client, advanced mechanisms such as Apple's Intelligent Tracking Protection (ITP) may block or drop the cookie, resulting in unmatched users.

To overcome this, use a two-step anonymous session transfer mechanism that does not rely on cookies:

1. Call the `/anonymous/token` endpoint, requesting the `urn:auth0:anon_transfer_token` audience, to receive an `anon_transfer_token` in exchange.
2. Include the `anon_transfer_token` as a parameter in the `/authorize` call.

The `anon_transfer_token` is bound to the IP address that requested it. If you plan to use this cookieless mechanism for login, Auth0 recommends turning off the issuance of anonymous session cookies in your [tenant settings](/docs/manage-users/sessions/anonymous-sessions/configure-anonymous-sessions#configure-anonymous-sessions-in-your-auth0-tenant) to avoid undesired clashes or injections.

```mermaid actions={false} theme={null}
sequenceDiagram
  participant app as SPA/APP
  participant idp as Auth0
  alt Login with cookie
    app ->>+ idp: GET /authorize?client_id=xxx...<br>Cookie: auth0_anon=eyJ...
  else Login with anonymous transfer token
    app ->> idp: POST /anonymous/token<br>{audience: "urn:auth0:anon_transfer_token"}
    idp ->> app: anon_transfer_token, expires in: 30
    app ->>+ idp: GET /authorize?client_id=xxx...&anon_transfer_token=<att>
  end
  note over app,idp: Login ceremonies
  idp ->> idp: Run post-login/pre-registration<br>includes event.anonymous_session
  note over app,idp: Auth Code Callback
  idp ->>- app: HTTP 200 OK <br> Access Token, ID Token...
```

Upon successful login, Auth0 makes the anonymous session data available in your [`pre-user-registration`](/docs/customize/actions/explore-triggers/signup-and-login-triggers/pre-user-registration-trigger) and [`post-login`](/docs/customize/actions/explore-triggers/signup-and-login-triggers/login-trigger) Actions triggers using the `event.anonymous_session` object.

```json anonymous session object theme={null}
{
  "anonymous_session": {
    "user_id": "anon@1234-5678-90",
    "session_id": "sess_123",
    "created_at": "2026-05-14T10:30:00Z",
    "metadata": {
      "language": "en",
      "country": "US",
      "order_id": "PO123"
    }
  }
}
```

#### Transferring a session in a Resource Owner Password Grant (ROPG) scenario

When using ROPG for login, include the `anonymous_session_token` in the request body of the `/oauth/token` call:

```http Anonymous session token in a ROPG request theme={null}
POST /oauth/token HTTP/1.1

username=<username>&
password=<password>&
client_id=<client_id>&
scope=<desired scopes>&
grant_type=http://auth0.com/oauth/grant-type/password-realm&
client_secret=<secret>&
realm=<database or realm>&
audience=<desired audience>&
anonymous_session_token=ANONYMOUS_SESSION_eyJ...
```

To learn more about anonymous sessions with Actions, read [Anonymous Sessions Use Cases](/docs/manage-users/sessions/anonymous-sessions/anonymous-sessions-use-cases).

### End the anonymous session after transfer

Anonymous session cookies are not automatically flushed when a user authenticates, so the cookie can continue to be sent in subsequent logins. To end the session, use the `/anonymous/logout` endpoint:

```javascript wrap lines theme={null}
// In your application, after successful login
if (wasAnonymousSession) {
  await fetch('https://YOUR_DOMAIN/anonymous/logout', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    credentials: 'include', // Send cookies
    body: JSON.stringify({ client_id: 'YOUR_CLIENT_ID' }),
  });
}
```

Auth0 does not offer server-side invalidation for anonymous sessions. Logging out a session only cleans up the anonymous session cookie — if the browser or application retains the token after the cookie is cleaned up, that token can still be used normally.

If you want more control over anonymous sessions, you can configure your tenant to not issue cookies for anonymous sessions at all — see [Configure anonymous sessions in your Auth0 tenant](/docs/manage-users/sessions/anonymous-sessions/configure-anonymous-sessions#configure-anonymous-sessions-in-your-auth0-tenant).

## Best practices

Here are some best practices for anonymous sessions:

* Configure appropriate [anonymous session lifetimes](/docs/manage-users/sessions/anonymous-sessions/configure-anonymous-sessions#configure-anonymous-sessions-in-your-auth0-tenant) to avoid losing a user's anonymous session data; Auth0 recommends a lifetime of 30 days or longer.

* Select anonymous session's [JSON Web Encryption (JWE)](/docs/manage-users/sessions/anonymous-sessions/configure-anonymous-sessions#configure-anonymous-sessions-in-your-auth0-tenant) encryption to ensure that potential attackers cannot see the contents of the session.

* Restrict what anonymous `anon@` users can do in your API.

* Validate tokens and sanitize metadata, never trust metadata or tokens from clients without server-side validation.

* Cache [access tokens](/docs/secure/tokens/access-tokens) since they can be reused until they expire.

* Batch and minimize metadata updates. Avoid frequent metadata updates.

## Limitations

* [Password reset](/docs/customize/actions/explore-triggers/password-reset-triggers#password-reset-triggers) flows are not supported by anonymous sessions.
* [Device Code](/docs/get-started/authentication-and-authorization-flow/device-authorization-flow) is not supported because the authentication request and the actual login happen on different devices.
* [Client-Initiated Backchannel Authentication (CIBA)](/docs/get-started/applications/configure-client-initiated-backchannel-authentication) is not supported because the authentication request and confirmation happen on different devices.
* [Custom token exchange](/docs/authenticate/custom-token-exchange/cte-example-use-cases) is not supported due to the nature of the transactions (for example, impersonation), which creates a likelihood of attributing anonymous data to the wrong user.
* [Refresh token exchange](/docs/secure/call-apis-on-users-behalf/token-vault/configure-token-vault#configure-token-exchange) is not supported by anonymous sessions because the user is already logged in if they had a refresh token.

## Learn more

* [Configure Anonymous Sessions](/docs/manage-users/sessions/anonymous-sessions/configure-anonymous-sessions) Learn how to configure anonymous sessions.
* [Configure Custom Claims for Anonymous Sessions](/docs/manage-users/sessions/anonymous-sessions/configure-custom-claims-for-anonymous-sessions) Learn how to map anonymous session metadata into access token claims.
* [Anonymous Sessions Use Cases](/docs/manage-users/sessions/anonymous-sessions/anonymous-sessions-use-cases) Learn about anonymous sessions use cases.
