> ## Documentation Index
> Fetch the complete documentation index at: https://www.commercengine.io/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Authentication

> Authentication verifies the identity of the user interacting with your storefront. Commerce Engine uses a robust token-based system (JWT) and offers flexible login methods, including passwordless options via Email, Phone, and WhatsApp.

<Info>
  **Authentication Overview**

  * **Tokens:** Authentication relies on **Access Tokens** and **Refresh Tokens**.
    * **Access Token:** A short-lived Bearer token sent in the `Authorization` header of most API requests. It proves the user's identity for a limited time.
    * **Refresh Token:** A longer-lived token used *only* to request a new Access Token when the current one expires. It should be stored securely and used less frequently.
  * **User States:**
    * **Anonymous User:** A user who hasn't logged in or registered. They get tokens via `POST /auth/anonymous` (using the `X-Api-Key`). These tokens allow basic browsing, cart management, and crucially, enable server-side analytics tracking from the start.
    * **Logged-in User:** A user who has verified their identity via OTP (Email, Phone, WhatsApp) or potentially a password. They receive *new, more privileged* Access and Refresh tokens upon successful verification. These tokens grant access to sensitive endpoints like order history, address book, etc.
  * **Security:** Always transmit tokens over HTTPS. Store tokens securely on the client (e.g., HttpOnly cookies for web, secure storage for mobile).

  <Warning>
    **API Key Security**

    The `X-Api-Key` is a publishable key and so it is fine for you to include it in your frontend code.
  </Warning>
</Info>

### Anonymous Authentication

As shown in Getting Started, this is the **first step** for any new visitor to your storefront.

**Endpoint:** `POST /auth/anonymous`

**Authentication:** Requires `X-Api-Key` header.

**Purpose:**

1. Assigns a unique `user.id` to track the visitor immediately.
2. Provides initial `access_token` and `refresh_token` for the session.
3. Enables automatic server-side analytics event tracking for the user's actions (viewing products, adding to cart, etc.) right from the start.

<Frame caption="Anonymous Auth Flow">
  <iframe title="Anonymous Auth Flow" allowfullscreen width="100%" height="300" src="https://mermaid.tarkai.dev/embed?definition=sequenceDiagram%0A%20%20%20%20participant%20ClientApp%20as%20Client%20Application%0A%20%20%20%20participant%20CE_API%20as%20CE%20API%0A%0A%20%20%20%20ClientApp-%3E%3ECE_API%3A%20POST%20%2Fauth%2Fanonymous%20(Header%3A%20X-Api-Key)%0A%20%20%20%20activate%20CE_API%0A%20%20%20%20CE_API--%3E%3EClientApp%3A%20200%20OK%20(Response%3A%20%7Buser%2C%20access_token%2C%20refresh_token%7D)%0A%20%20%20%20deactivate%20CE_API%0A%20%20%20%20ClientApp-%3E%3EClientApp%3A%20Store%20access_token%20%26%20refresh_token%20securely" />
</Frame>

**Using the Anonymous Token:** Include the received `access_token` as a Bearer token in the `Authorization` header for subsequent API calls, like fetching products:

```bash Using Anonymous Token theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl GET /catalog/products \
  --header 'Authorization: Bearer ACCESS_TOKEN'
```

### Passwordless Login & Registration

Commerce Engine prioritizes frictionless login experiences using One-Time Passwords (OTPs) sent via Email, Phone, or WhatsApp. This flow also seamlessly handles registration for new users.

The login flow is the recommended way to implement checkout when building storefronts, especially for brands selling physical goods that need to be shipped. Having a validated email/phone early in the checkout flow reduce overall friction, minimize RTOs due to incorrect contact details and make it easier for your customers to access protected endpoints like Order Details after an order is successfully placed.

<Info>
  **Key Feature: `register_if_not_exists`**

  When initiating a login (`POST /auth/login/*`), you can include the flag `"register_if_not_exists": true` in the request body.

  * **If the user exists:** An OTP is sent for login verification.
  * **If the user *does not* exist:** Commerce Engine *automatically creates a basic user record* associated with the provided email/phone and sends an OTP for verification *and* implicit registration.

  This eliminates the need for users to guess if they have an account and removes the requirement for separate "Login" vs. "Sign Up" flows or distinct "Guest Checkout" paths. Every user starts the same way.
</Info>

**The Flow (Email/Phone/WhatsApp):**

<Steps titleSize="h3">
  <Step title="Initiate Login">
    The user provides their email address, phone number, or WhatsApp number. Your application calls the corresponding login endpoint:

    * `POST /auth/login/email` (Body: `{ "email": "...", "register_if_not_exists": true }`)
    * `POST /auth/login/phone` (Body: `{ "phone": "...", "country_code": "+91", "register_if_not_exists": true }`)
    * `POST /auth/login/whatsapp` (Body: `{ "phone": "...", "country_code": "+91", "register_if_not_exists": true }`)

    *Authentication:* Requires a valid (anonymous or logged-in) `Bearer` token.

    ```bash Initiate Email Login Example theme={"theme":{"light":"github-light","dark":"github-dark"}}
    curl -X POST 'YOUR_BASE_URL/auth/login/email' \
      --header 'Authorization: Bearer YOUR_ACCESS_TOKEN' \
      --header 'Content-Type: application/json' \
      --data '{
        "email": "user@example.com",
        "register_if_not_exists": true
      }'
    ```
  </Step>

  <Step title="Receive OTP Token">
    Commerce Engine sends an OTP to the specified channel and responds to your app with:

    ```json Initiate Login Response theme={"theme":{"light":"github-light","dark":"github-dark"}}
    {
      "message": "OTP sent successfully.",
      "success": true,
      "content": {
        "otp_token": "a_temporary_token_representing_this_otp_attempt",
        "otp_action": "login" // Or "register" if register_if_not_exists triggered creation
      }
    }
    ```

    * `otp_token`: A temporary token associated with this specific OTP verification attempt.
    * `otp_action`: Confirms the context (usually `login` or potentially `register`).
  </Step>

  <Step title="User Enters OTP">
    Display an input field for the user to enter the OTP they received.
  </Step>

  <Step title="Verify OTP">
    Send the user-entered OTP and the `otp_token` back to Commerce Engine:

    * **Endpoint:** `POST /auth/verify-otp`
    * **Authentication:** Requires a valid (anonymous or logged-in) `Bearer` token.
    * **Body:**

    ```json Verify OTP Request Body theme={"theme":{"light":"github-light","dark":"github-dark"}}
    {
      "otp": "USER_ENTERED_OTP",
      "otp_token": "the_otp_token_received_in_step_2",
      "otp_action": "login" // From step 2
    }
    ```

    ```bash Verify OTP Example theme={"theme":{"light":"github-light","dark":"github-dark"}}
    curl -X POST 'YOUR_BASE_URL/auth/verify-otp' \
      --header 'Authorization: Bearer YOUR_ACCESS_TOKEN' \
      --header 'Content-Type: application/json' \
      --data '{
        "otp": "123456",
        "otp_token": "the_otp_token_received_in_step_2",
        "otp_action": "login"
      }'
    ```
  </Step>

  <Step title="Login Success & New Tokens">
    If the OTP is correct, Commerce Engine verifies the user (or completes the registration) and responds with:

    ```json Verify OTP Success Response theme={"theme":{"light":"github-light","dark":"github-dark"}}
    {
      "message": "OTP verified successfully. User logged in.",
      "success": true,
      "content": {
        "user": {
          "id": "01HXXXXXXLOGGEDINUSERID",
          "first_name": "...", // May be null if just registered
          "last_name": "...", // May be null if just registered
          "email": "user@example.com",
          "is_email_verified": true,
          "phone": "9988776655",
          "country_code": "+91",
          "is_phone_verified": true,
          "profile_image_url": null,
          "is_anonymous": false,
          "is_logged_in": true, // Use this key to create auth guards or protected routes
          "login_methods": ["email", "phone"]
          // ... other user details
        },
        "access_token": "NEW_PRIVILEGED_ACCESS_TOKEN_eyJ...",
        "refresh_token": "NEW_PRIVILEGED_REFRESH_TOKEN_abc..."
      }
    }
    ```

    <Warning>
      **Important: Update Tokens**

      * **Crucially:** You receive a **new** `access_token` and `refresh_token`. These tokens are associated with the now *logged-in* user and have higher privileges than the initial anonymous tokens.
      * **Replace the old (anonymous) tokens** in your secure storage with these new ones.
      * The `user` object now contains the details of the logged-in user. `is_anonymous` is `false`, and `is_logged_in` is `true`.
    </Warning>
  </Step>
</Steps>

**Passwordless Login/Registration Flow Diagram:**

<Frame caption="Passwordless Flow">
  <iframe title="Passwordless Flow Diagram" allowfullscreen width="100%" height="800" src="https://mermaid.tarkai.dev/embed?definition=sequenceDiagram%0A%20%20%20%20participant%20ClientApp%20as%20Client%20Application%0A%20%20%20%20participant%20User%0A%20%20%20%20participant%20CE_API%20as%20CE%20API%0A%20%20%20%20participant%20OTP_Service%20as%20OTP%20Service%0A%0A%20%20%20%20User-%3E%3EClientApp%3A%20Enters%20Email%2FPhone%0A%20%20%20%20ClientApp-%3E%3ECE_API%3A%20POST%20%2Fauth%2Flogin%2F%7Bchannel%7D%0A%20%20%20%20activate%20CE_API%0A%20%20%20%20alt%20User%20Exists%20OR%20register_if_not_exists%3Dtrue%0A%20%20%20%20%20%20%20%20CE_API-%3E%3EOTP_Service%3A%20Send%20OTP%0A%20%20%20%20%20%20%20%20OTP_Service--%3E%3EUser%3A%20Delivers%20OTP%0A%20%20%20%20%20%20%20%20CE_API--%3E%3EClientApp%3A%20200%20OK%20(otp_token%2C%20otp_action)%0A%20%20%20%20else%20User%20Not%20Found%20AND%20register_if_not_exists%3Dfalse%0A%20%20%20%20%20%20%20%20CE_API--%3E%3EClientApp%3A%20Error%20(e.g.%2C%20404)%0A%20%20%20%20end%0A%20%20%20%20deactivate%20CE_API%0A%0A%20%20%20%20User-%3E%3EClientApp%3A%20Enters%20Received%20OTP%0A%20%20%20%20ClientApp-%3E%3ECE_API%3A%20POST%20%2Fauth%2Fverify-otp%0A%20%20%20%20activate%20CE_API%0A%20%20%20%20alt%20OTP%20Correct%0A%20%20%20%20%20%20%20%20CE_API-%3E%3ECE_API%3A%20Verify%20User%20%2F%20Register%0A%20%20%20%20%20%20%20%20CE_API--%3E%3EClientApp%3A%20200%20OK%20(user%20%5Blogged-in%5D%2C%20new_access_token%2C%20new_refresh_token)%0A%20%20%20%20%20%20%20%20ClientApp-%3E%3EClientApp%3A%20Store%20NEW%20tokens.%20Update%20state.%0A%20%20%20%20else%20OTP%20Incorrect%0A%20%20%20%20%20%20%20%20CE_API--%3E%3EClientApp%3A%20Error%20(e.g.%2C%20400)%0A%20%20%20%20end%0A%20%20%20%20deactivate%20CE_API" />
</Frame>

**Updating User Profile:**

If a user signs up using only their email/phone via the `register_if_not_exists` flow, their `first_name` and `last_name` might be null. You can allow them to update their profile later using:

* **Endpoint:** `PUT /auth/user/{id}`
* **Authentication:** Requires a **logged-in** user's `Bearer` token.
* **Path Parameter:** `{id}` is the `user.id` obtained during login/verification.
* **Request Body:** Send the fields to update (e.g., `first_name`, `last_name`). See the `User` schema.

```bash Update User Profile Example theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl -X PUT \
  'https://staging.api.commercengine.io/api/v1/YOUR_STORE_ID/storefront/auth/user/USER_ID' \
  --header 'Authorization: Bearer LOGGED_IN_ACCESS_TOKEN' \
  --header 'Content-Type: application/json' \
  --data '{
    "first_name": "Rajesh",
    "last_name": "Kumar"
  }'
```

<Tip>
  When a new user adds an address, their first and last name will be
  automatically updated.
</Tip>

### Other Authentication Endpoints

While passwordless is recommended, Commerce Engine provides other endpoints for different scenarios:

* **Generate OTP (`POST /auth/generate-otp`):** Useful if you need to trigger OTP generation outside the main login flow (e.g., verifying a phone number added to a profile). Specify the `channel` (sms, email, whatsapp) and `otp_action` (e.g., `verify-phone`, `update-email`). Requires a bearer token.
* **Check Verification Status (`POST /auth/verified-email-phone`):** Check if specific emails or phone numbers are already marked as verified in the system. Requires a bearer token.
* **Password Login (`POST /auth/login/password`):** Allows login using email/phone and password. Returns new tokens on success. Requires a bearer token (can be anonymous).
* **Change Password (`POST /auth/change-password`):** For logged-in users to change their password. Requires `old_password`, `new_password`, `confirm_password`. Requires a **logged-in** bearer token.
* **Forgot Password (`POST /auth/forgot-password`):** Initiates the password reset flow, sending an OTP. Requires email or phone. Requires a bearer token (can be anonymous). Responds with an `otp_token`.
* **Reset Password (`POST /auth/reset-password`):** Completes the password reset using the `otp_token` from the forgot password flow and the `new_password`. Requires a bearer token (can be anonymous). Returns new tokens on success.

## Token Management

Properly managing Access and Refresh tokens is vital for security and user experience.

<Steps>
  <Step title="Secure Storage">
    <Warning>
      **Security Best Practices**

      * **Web:** Store tokens securely. **HttpOnly cookies** are often recommended as they are not accessible via client-side JavaScript, mitigating XSS risks. Alternatively, use browser storage (localStorage/sessionStorage) but be mindful of XSS vulnerabilities.
      * **Mobile:** Use the platform's secure storage mechanisms (Keychain on iOS, Keystore/EncryptedSharedPreferences on Android).
      * **Never store tokens insecurely (e.g., plain localStorage without XSS protection).**
    </Warning>
  </Step>

  <Step title="Using Access Tokens">
    Include the `access_token` in the `Authorization: Bearer <token>` header for all API calls (except `POST /auth/anonymous`).
  </Step>

  <Step title="Handling Expiry & Refreshing">
    Access tokens are short lived Json Web Tokens (JWTs).

    * **Proactive Refresh:** Decode the access token (the payload is not encrypted) to check its expiry time (`exp` claim). Before it expires, use the `refresh_token` to get a new pair of tokens.
    * **Reactive Refresh:** If an API call returns a `401 Unauthorized` error, it likely means the access token expired. Use the `refresh_token` to get a new pair, then retry the original API call with the new `access_token`.
    * **Refresh Endpoint:** `POST /auth/refresh-token`
    * **Authentication:** Requires a valid (anonymous or logged-in) `Bearer` token.
    * **Request Body:**

    ```json Refresh Token Request Body theme={"theme":{"light":"github-light","dark":"github-dark"}}
    { "refresh_token": "YOUR_STORED_REFRESH_TOKEN" }
    ```

    * **Response (Success):**

    ```json Refresh Token Success Response theme={"theme":{"light":"github-light","dark":"github-dark"}}
    {
      "message": "Token refreshed successfully.",
      "success": true,
      "content": {
        "access_token": "NEW_ACCESS_TOKEN_xyz...",
        "refresh_token": "POSSIBLY_NEW_REFRESH_TOKEN_123..." // Refresh tokens might rotate
      }
    }
    ```

    * **Update Storage:** Replace the old tokens with the new ones received from the refresh endpoint.
    * **Refresh Token Failure:** If the refresh token itself is invalid or expired, the user must log in again.

    **Token Refresh Flow Diagram:**

    <Frame caption="Token Refresh Flow">
      <iframe title="Token Refresh Flow Diagram" allowfullscreen width="100%" height="700" src="https://mermaid.tarkai.dev/embed?definition=sequenceDiagram%0A%20%20%20%20participant%20ClientApp%20as%20Client%20Application%0A%20%20%20%20participant%20CE_API%20as%20CE%20API%0A%0A%20%20%20%20ClientApp-%3E%3ECE_API%3A%20API%20Request%20%28Header%3A%20Auth%20Bearer%20%5BExpired%20Token%5D%29%0A%20%20%20%20activate%20CE_API%0A%20%20%20%20CE_API--%3E%3EClientApp%3A%20401%20Unauthorized%0A%20%20%20%20deactivate%20CE_API%0A%0A%20%20%20%20ClientApp-%3E%3ECE_API%3A%20POST%20/auth/refresh-token%20%28Body%3A%20%7Brefresh_token%7D%2C%20Header%3A%20Auth%20Bearer%20%5BExpired%20Token%5D%29%0A%20%20%20%20activate%20CE_API%0A%20%20%20%20alt%20Refresh%20Token%20Valid%0A%20%20%20%20%20%20%20%20CE_API--%3E%3EClientApp%3A%20200%20OK%20%28Response%3A%20%7Bnew_access_token%2C%20new_refresh_token%7D%29%0A%20%20%20%20%20%20%20%20ClientApp-%3E%3EClientApp%3A%20Store%20NEW%20tokens%2C%20replace%20old%20ones.%0A%20%20%20%20%20%20%20%20ClientApp-%3E%3ECE_API%3A%20Retry%20Original%20API%20Request%20%28Header%3A%20Auth%20Bearer%20%5BNew%20Token%5D%29%0A%20%20%20%20%20%20%20%20activate%20CE_API%0A%20%20%20%20%20%20%20%20CE_API--%3E%3EClientApp%3A%20200%20OK%20%28Original%20Request%20Successful%29%0A%20%20%20%20%20%20%20%20deactivate%20CE_API%0A%20%20%20%20else%20Refresh%20Token%20Invalid/Expired%0A%20%20%20%20%20%20%20%20CE_API--%3E%3EClientApp%3A%20Error%20%28e.g.%2C%20401%20Unauthorized%20-%20Invalid%20Refresh%20Token%29%0A%20%20%20%20%20%20%20%20ClientApp-%3E%3EClientApp%3A%20Clear%20stored%20tokens.%20Redirect%20User%20to%20Login.%0A%20%20%20%20end%0A%20%20%20%20deactivate%20CE_API" />
    </Frame>

    ```bash Refresh Token Example theme={"theme":{"light":"github-light","dark":"github-dark"}}
    curl -X POST 'YOUR_BASE_URL/auth/refresh-token' \
      --header 'Authorization: Bearer ANY_VALID_ACCESS_TOKEN' \
      --header 'Content-Type: application/json' \
      --data '{
        "refresh_token": "YOUR_STORED_REFRESH_TOKEN"
      }'
    ```

    ### Handling Expired Refresh Tokens (Long User Absence)

    What happens if a user returns to your app after a long time, and *both* their access token and refresh token have expired? Attempting to use the refresh token will fail.

    <Tip>
      **Best Practice: Handling Long Absences**

      1. **On App Load:** Always attempt to validate the user's session. A common way is to try refreshing the token immediately (`POST /auth/refresh-token`). If that fails, or if you have no tokens stored, proceed to the next step.
      2. **Re-authenticate Anonymously:** Call `POST /auth/anonymous` again.
      3. **Preserve User ID:** To ensure continuity for analytics and user history, **include the *expired* access token** (if you still have it) in the `Authorization: Bearer` header of the `POST /auth/anonymous` request.
         * Commerce Engine intelligently recognizes the expired token, finds the associated `user_id`, and issues **new anonymous access and refresh tokens** linked to that **same existing `user_id`**.
         * If no expired token is sent, a completely new anonymous user ID and tokens will be generated.
    </Tip>

    **Expired Token Recovery Flow:**

    <Frame caption="Expired Token Recovery Flow">
      <iframe title="Expired Token Recovery Flow Diagram" allowfullscreen width="100%" height="500" src="https://mermaid.tarkai.dev/embed?definition=sequenceDiagram%0A%20%20%20%20participant%20ClientApp%20as%20Client%20Application%0A%20%20%20%20participant%20CE_API%20as%20CE%20API%0A%0A%20%20%20%20ClientApp-%3E%3EClientApp%3A%20App%20Load%20-%20Has%20Expired%20Tokens%0A%20%20%20%20ClientApp-%3E%3ECE_API%3A%20POST%20%2Fauth%2Frefresh-token%0A%20%20%20%20activate%20CE_API%0A%20%20%20%20CE_API--%3E%3EClientApp%3A%20401%20Unauthorized%20(Refresh%20Token%20Invalid%2FExpired)%0A%20%20%20%20deactivate%20CE_API%0A%0A%20%20%20%20ClientApp-%3E%3ECE_API%3A%20POST%20%2Fauth%2Fanonymous%20(Header%3A%20Auth%20Bearer%20%5BExpired%20Access%20Token%5D)%0A%20%20%20%20activate%20CE_API%0A%20%20%20%20CE_API-%3E%3ECE_API%3A%20Recognize%20expired%20token%2C%20find%20existing%20user_id%0A%20%20%20%20CE_API--%3E%3EClientApp%3A%20200%20OK%20(Response%3A%20%7Buser%20%5Banonymous%5D%2C%20NEW%20access_token%2C%20NEW%20refresh_token%7D%20for%20EXISTING%20user_id)%0A%20%20%20%20deactivate%20CE_API%0A%20%20%20%20ClientApp-%3E%3EClientApp%3A%20Store%20NEW%20anonymous%20tokens.%20User%20remains%20anonymous%20but%20linked%20to%20previous%20activity." />
    </Frame>

    This ensures that even after long absences, user activity remains tied to their original profile, providing valuable insights and enabling personalization upon eventual login.
  </Step>
</Steps>

## User Management & Preferences

Once a user is logged in, you can manage their profile and preferences:

* **Retrieve User:** `GET /auth/user/{id}` - Get full user details.
* **Update User:** `PUT /auth/user/{id}` - Update name, etc.
* **Notification Preferences:**
  * `GET /auth/user/{id}/notification-preferences` - Retrieve current settings.
  * `POST /auth/user/{id}/notification-preferences` - Create initial preferences (if not set).
  * `PUT /auth/user/{id}/notification-preferences` - Update preferences (allow users to opt-in/out of transactional, promotional, newsletter emails/SMS/WhatsApp). See `NotificationPreferences` schema.
* **Profile Image:** Manage user profile images (Requires `multipart/form-data`):
  * `POST /auth/user/{id}/profile-image` - Add image.
  * `PUT /auth/user/{id}/profile-image` - Update image.
  * `DELETE /auth/user/{id}/profile-image` - Remove image.
  * `GET /auth/user/{id}/profile-image` - Retrieve image URL.
* **Deactivate Account:** `PUT /auth/user/{id}/deactivate` - Mark the user account as inactive.

## Logout

To log a user out, you invalidate their current session tokens server-side and clear them client-side.

* **Endpoint:** `POST /auth/logout`
* **Authentication:** Requires a valid **logged-in** user's `Bearer` token.
* **Action:** Commerce Engine invalidates the associated refresh token server-side.
* **Response:** The API returns a `200 OK` response containing:
  * The `user` object, now updated to reflect an anonymous state (`is_anonymous: true`, `is_logged_in: false`).
  * A **new set of anonymous** `access_token` and `refresh_token`, linked to the **same `user_id`**.
* **Client-Side Action:**
  1. **Clear Old Tokens:** Securely remove the previous (logged-in) `access_token` and `refresh_token` from storage.
  2. **Store New Anonymous Tokens:** Store the new anonymous tokens received in the response.
  3. **Update Local State:** **Crucially, update your application's local user state** (e.g., in your state management library) using the `user` object provided in the logout response. This ensures your UI correctly reflects the now-anonymous status while retaining the underlying `user_id`.

<Tip>
  **State Management Best Practice**

  To simplify client-side state management and avoid conflicts, **always update your local user state object based on the `user` object returned by Commerce Engine API responses** (like Login, Verify OTP, Refresh Token, Update User, and Logout). Treat the `user` object from CE as the source of truth for the user's current status and details.
</Tip>

**Logout Flow Diagram:**

<Frame caption="Logout Flow">
  <iframe title="Logout Flow Diagram" allowfullscreen width="100%" height="500" src="https://mermaid.tarkai.dev/embed?definition=sequenceDiagram%0A%20%20%20%20participant%20ClientApp%20as%20Client%20Application%0A%20%20%20%20participant%20CE_API%20as%20CE%20API%0A%0A%20%20%20%20ClientApp-%3E%3ECE_API%3A%20POST%20%2Fauth%2Flogout%20(Header%3A%20Auth%20Bearer%20%5BLogged-in%20Token%5D)%0A%20%20%20%20activate%20CE_API%0A%20%20%20%20CE_API-%3E%3ECE_API%3A%20Invalidate%20Refresh%20Token%20Server-Side%0A%20%20%20%20CE_API--%3E%3EClientApp%3A%20200%20OK%20(Response%3A%20%7Buser%20%5Bnow%20anonymous%5D%2C%20new_anon_access_token%2C%20new_anon_refresh_token%7D)%0A%20%20%20%20deactivate%20CE_API%0A%20%20%20%20ClientApp-%3E%3EClientApp%3A%20Clear%20old%20tokens%20from%20storage%0A%20%20%20%20ClientApp-%3E%3EClientApp%3A%20Store%20NEW%20anonymous%20tokens%0A%20%20%20%20ClientApp-%3E%3EClientApp%3A%20Update%20local%20user%20state%20with%20user%20object%20from%20response%0A%20%20%20%20ClientApp-%3E%3EClientApp%3A%20Update%20UI%20to%20logged-out%20state" />
</Frame>

```bash Logout Example theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl -X POST 'YOUR_BASE_URL/auth/logout' \
  --header 'Authorization: Bearer LOGGED_IN_ACCESS_TOKEN'
```
