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

# Backend Token Widget Authentication

> Authenticate the Notification Center widget with HMAC tokens generated by your backend via `client.generateHashedToken(userId)`.

# Backend token widget authentication

Backend token authentication ties the widget session to your existing auth system. Your backend HMAC-signs a token per user with the Notifizz Node SDK, and the frontend passes it (with `userId` and `userEmail`) to the widget. Notifizz recomputes the HMAC server-side and accepts the session only if they match.

## TL;DR

* **Server-side:** `const token = client.generateHashedToken(userId)` — SHA-256 of `userId + authSecretKey`.
* **Client-side:** widget options include `authType: 'backendToken'`, `token`, `userId`, `userEmail`.
* **Identity proof:** Notifizz recomputes the hash with its own `authSecretKey` and compares — no external IDP roundtrip.
* **Recommended for production** when you have your own auth and don't already use Firebase.

## How it works

```mermaid theme={null}
sequenceDiagram
    participant Frontend
    participant Backend as Your backend
    participant Notifizz

    Frontend->>Backend: User logs in
    Backend->>Backend: client.generateHashedToken(userId)
    Backend->>Frontend: Return token + user info
    Frontend->>Notifizz: Mount widget with token + userId + userEmail
    Notifizz-->>Notifizz: Recompute hash, compare
    Notifizz->>Frontend: Connected — notifications flow
```

<Steps>
  <Step title="User logs in">
    Your app authenticates the user through your existing system.
  </Step>

  <Step title="Backend mints the token">
    Call `client.generateHashedToken(userId)` from the [Notifizz Node SDK](/docs/sdks/event-tracking/node-js). It returns the hex-encoded SHA-256 of `userId + authSecretKey`.
  </Step>

  <Step title="Token shipped to frontend">
    Return the token alongside the login response or expose a dedicated `/me/notifizz-token` endpoint.
  </Step>

  <Step title="Widget authenticates">
    The frontend passes `token`, `userId`, `userEmail` to the widget. Notifizz recomputes the hash and accepts the session if it matches.
  </Step>
</Steps>

## Backend setup

```javascript theme={null}
import { NotifizzClient } from "@notifizz/nodejs";

const client = new NotifizzClient(
  process.env.NOTIFIZZ_AUTH_SECRET_KEY,
  process.env.NOTIFIZZ_SDK_SECRET_KEY,
);

// In your login endpoint or session handler:
const token = client.generateHashedToken("u_42");
return res.json({ notifizzToken: token, userId: "u_42", userEmail: "alice@example.com" });
```

`generateHashedToken()` is deterministic — the same `userId` always produces the same token until you rotate `authSecretKey`. It does not perform a network call.

The Java and PHP SDKs expose the same helper:

<CodeGroup>
  ```java Java theme={null}
  String token = client.generateHashedToken("u_42");
  ```

  ```php PHP theme={null}
  $token = $client->generateHashedToken('u_42');
  ```
</CodeGroup>

## Frontend setup

<Tabs>
  <Tab title="React">
    ```jsx theme={null}
    <NotifizzInbox
      options={{
        apiKey: "YOUR_FRONT_API_KEY",
        authType: "backendToken",
        token: tokenFromBackend,
        userId: "u_42",
        userEmail: "alice@example.com",
      }}
    />
    ```
  </Tab>

  <Tab title="Angular">
    ```html theme={null}
    <notifizz-bell
      [options]="{
        apiKey: 'YOUR_FRONT_API_KEY',
        authType: 'backendToken',
        token: tokenFromBackend,
        userId: 'u_42',
        userEmail: 'alice@example.com'
      }"
    ></notifizz-bell>
    ```
  </Tab>

  <Tab title="Vanilla JS">
    ```javascript theme={null}
    const notifizz = createNotifizz({
      apiKey: "YOUR_FRONT_API_KEY",
      authType: "backendToken",
      token: tokenFromBackend,
      userId: "u_42",
      userEmail: "alice@example.com",
    });
    ```
  </Tab>
</Tabs>

## Required fields

| Field       | Type             | Description                                                  |
| ----------- | ---------------- | ------------------------------------------------------------ |
| `authType`  | `'backendToken'` | Mandatory literal.                                           |
| `token`     | `string`         | The output of `client.generateHashedToken(userId)`.          |
| `userId`    | `string`         | Must match the `userId` you passed to `generateHashedToken`. |
| `userEmail` | `string`         | The user's email address.                                    |

## Security

<Warning>
  Never expose `authSecretKey` on the frontend. Token generation happens server-side only. The frontend only ever sees the resulting token.
</Warning>

The token is bound to the `userId` it was minted for — an intercepted token only unlocks that user's inbox, not anyone else's. Rotate `authSecretKey` (in the dashboard) when you suspect compromise; all previously minted tokens become invalid and your backend will mint new ones on the next session.

## FAQ

<AccordionGroup>
  <Accordion title="Where in the dashboard do I find `authSecretKey`?">
    Environment settings → API keys. There are two server-side keys: `authSecretKey` (for `generateHashedToken`) and `sdkSecretKey` (for `track()`). Don't confuse them — using the wrong one yields a 401 when the widget tries to authenticate.
  </Accordion>

  <Accordion title="Same `userId`, same token — is that a problem?">
    No. The token is deterministic by design — it's a function of `userId + authSecretKey`. Anyone who has the token can act as that user, but cannot derive a token for another user. Rotate `authSecretKey` to invalidate existing tokens.
  </Accordion>

  <Accordion title="How do I rotate `authSecretKey` without downtime?">
    Notifizz accepts a short overlap window where both the old and the new key are valid (configurable in the dashboard). Mint with the old key, deploy your backend to mint with the new key, wait the overlap window, retire the old key. Existing widget sessions stay alive.
  </Accordion>

  <Accordion title="The widget shows `hasError: true` after login.">
    Most likely the `userId` you passed to the widget doesn't match the `userId` you passed to `generateHashedToken`. Double-check both — even a string-vs-number mismatch breaks the hash. Inspect `state.errorCode` for a typed signal.
  </Accordion>

  <Accordion title="Can I generate the token from a serverless function?">
    Yes — `generateHashedToken` is a pure SHA-256 computation, no network call. It runs fine in any serverless runtime that has the Notifizz Node SDK installed (or you can implement the same hash manually — see the SDK source).
  </Accordion>

  <Accordion title="Can I cache the token on the frontend?">
    Yes — the token is stable for as long as `authSecretKey` doesn't rotate. Many apps cache it in a session cookie or `localStorage` and re-mint only on rotation. Don't share it across origins.
  </Accordion>
</AccordionGroup>

## See also

<CardGroup cols={2}>
  <Card title="Authentication overview" icon="key" href="/docs/sdks/authentication/overview">
    The four-mode model and when to pick each.
  </Card>

  <Card title="Node.js SDK reference" icon="node-js" href="/docs/sdks/event-tracking/node-js">
    Full reference for `generateHashedToken()` and the rest of the API.
  </Card>

  <Card title="Firebase auth" icon="fire" href="/docs/sdks/authentication/firebase">
    Skip the backend work if you use Firebase Auth.
  </Card>

  <Card title="Publicly-signed JWT" icon="shield" href="/docs/sdks/authentication/publicly-signed-jwt">
    Decouple widget auth from your backend with a managed IDP.
  </Card>
</CardGroup>
