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

# Notifizz Auth Integration Recipes

> Per-stack code examples for the four widget auth modes — Express, Fastify, NestJS, Laravel, Django, Rails, Next.js, Auth0, Clerk.

# Auth integration recipes

This page collects copy-pasteable recipes for each widget auth mode against the most common backend and identity-provider stacks. The conceptual reference is in [authentication overview](/docs/sdks/authentication/overview); the per-mode details are under each auth-mode page.

## TL;DR

* **`backendToken`** — your backend exposes a token endpoint; recipes per backend framework below.
* **`firebase`** — your frontend reads the Firebase ID token; minimal backend involvement.
* **`PubliclySignedJwt`** — your frontend reads the IDP's session token; configured server-side in the dashboard.
* **`none`** — local dev only; no auth.

## Backend Token recipes

### Node — Express

```javascript theme={null}
import express from "express";
import { NotifizzClient } from "@notifizz/nodejs";
import { requireAuth } from "./auth-middleware.js";

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

const app = express();

app.get("/api/notifizz-session", requireAuth, (req, res) => {
  const token = notifizz.generateHashedToken(req.user.id);
  res.json({
    token,
    userId: req.user.id,
    userEmail: req.user.email,
  });
});
```

### Node — Fastify

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

const fastify = Fastify();
const notifizz = new NotifizzClient(/* ... */);

fastify.get("/api/notifizz-session", { preHandler: requireAuth }, async (req) => {
  return {
    token: notifizz.generateHashedToken(req.user.id),
    userId: req.user.id,
    userEmail: req.user.email,
  };
});
```

### Node — NestJS

```typescript theme={null}
import { Controller, Get, Req } from "@nestjs/common";
import { NotifizzClient } from "@notifizz/nodejs";

@Controller("api")
export class NotifizzController {
  private notifizz = new NotifizzClient(/* ... */);

  @Get("notifizz-session")
  getSession(@Req() req) {
    return {
      token: this.notifizz.generateHashedToken(req.user.id),
      userId: req.user.id,
      userEmail: req.user.email,
    };
  }
}
```

### PHP — Laravel

```php theme={null}
use Notifizz\NotifizzClient;
use Illuminate\Support\Facades\Route;
use Illuminate\Support\Facades\Auth;

Route::middleware('auth')->get('/api/notifizz-session', function () {
    $client = new NotifizzClient(
        config('services.notifizz.auth_secret'),
        config('services.notifizz.sdk_secret'),
    );
    $user = Auth::user();
    return [
        'token' => $client->generateHashedToken((string) $user->id),
        'userId' => (string) $user->id,
        'userEmail' => $user->email,
    ];
});
```

### Python — Django

```python theme={null}
import hashlib
from django.http import JsonResponse
from django.contrib.auth.decorators import login_required
import os

@login_required
def notifizz_session(request):
    user_id = str(request.user.id)
    auth_secret = os.environ["NOTIFIZZ_AUTH_SECRET_KEY"]
    token = hashlib.sha256((user_id + auth_secret).encode()).hexdigest()
    return JsonResponse({
        "token": token,
        "userId": user_id,
        "userEmail": request.user.email,
    })
```

There's no official Python SDK yet — the helper is two lines: `hashlib.sha256((user_id + auth_secret).encode()).hexdigest()`. The hash format is the same as `client.generateHashedToken()` in the Node/Java/PHP SDKs.

### Ruby — Rails

```ruby theme={null}
require "digest"

class NotifizzController < ApplicationController
  before_action :authenticate_user!

  def session
    user_id = current_user.id.to_s
    token = Digest::SHA256.hexdigest(user_id + ENV["NOTIFIZZ_AUTH_SECRET_KEY"])
    render json: {
      token: token,
      userId: user_id,
      userEmail: current_user.email,
    }
  end
end
```

### Java — Spring

```java theme={null}
import com.notifizz.NotifizzClient;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/api")
public class NotifizzController {
    private final NotifizzClient notifizz = new NotifizzClient(
        System.getenv("NOTIFIZZ_AUTH_SECRET_KEY"),
        System.getenv("NOTIFIZZ_SDK_SECRET_KEY"));

    @GetMapping("/notifizz-session")
    public Map<String, String> getSession(Principal principal) {
        return Map.of(
            "token", notifizz.generateHashedToken(principal.getName()),
            "userId", principal.getName(),
            "userEmail", lookupEmail(principal.getName())
        );
    }
}
```

## Frontend consumption

Pair any of the backend recipes above with this frontend snippet:

```jsx theme={null}
// React example — works the same with Angular / Vanilla, just adapt the lifecycle
import { useEffect, useState } from "react";
import NotifizzInbox from "@notifizz/react";

function App() {
  const [session, setSession] = useState(null);

  useEffect(() => {
    fetch("/api/notifizz-session", { credentials: "include" })
      .then(r => r.json())
      .then(setSession);
  }, []);

  if (!session) return null;

  return (
    <NotifizzInbox
      options={{
        apiKey: process.env.REACT_APP_NOTIFIZZ_FRONT_API_KEY,
        authType: "backendToken",
        token: session.token,
        userId: session.userId,
        userEmail: session.userEmail,
      }}
    />
  );
}
```

## Firebase recipes

### Web client

```javascript theme={null}
import { getAuth, onAuthStateChanged } from "firebase/auth";

onAuthStateChanged(getAuth(), async (user) => {
  if (!user) return;
  const token = await user.getIdToken();
  mountNotifizz({ apiKey, authType: "firebase", token });
});
```

### Re-mount on token refresh

```javascript theme={null}
import { onIdTokenChanged } from "firebase/auth";

onIdTokenChanged(getAuth(), async (user) => {
  if (!user) return;
  const fresh = await user.getIdToken();
  setNotifizzToken(fresh);   // your component re-renders with the new token
});
```

## Publicly-Signed JWT recipes

`PubliclySignedJwt` is configured server-side via the dashboard. The frontend just reads the IDP session token. Common providers:

### Auth0

```javascript theme={null}
import { useAuth0 } from "@auth0/auth0-react";

const { getAccessTokenSilently, user } = useAuth0();
const token = await getAccessTokenSilently();
mountNotifizz({ apiKey, token, userId: user.sub, userEmail: user.email });
```

### Clerk

```javascript theme={null}
import { useAuth, useUser } from "@clerk/clerk-react";

const { getToken } = useAuth();
const { user } = useUser();
const token = await getToken();
mountNotifizz({
  apiKey,
  token,
  userId: user.id,
  userEmail: user.primaryEmailAddress.emailAddress,
});
```

### Cognito

```javascript theme={null}
import { fetchAuthSession, getCurrentUser } from "aws-amplify/auth";

const session = await fetchAuthSession();
const user = await getCurrentUser();
const token = session.tokens.idToken.toString();
mountNotifizz({
  apiKey,
  token,
  userId: user.userId,
  userEmail: user.signInDetails.loginId,
});
```

### Supabase Auth

```javascript theme={null}
import { createClient } from "@supabase/supabase-js";

const supabase = createClient(URL, KEY);
const { data: { session } } = await supabase.auth.getSession();
const { user } = session;
mountNotifizz({
  apiKey,
  token: session.access_token,
  userId: user.id,
  userEmail: user.email,
});
```

The dashboard `notificationCenterSetup` dev-task captures the JWKS URL + claim paths once per environment — the same frontend code works regardless of provider once the dashboard is configured. See [publicly-signed JWT](/docs/sdks/authentication/publicly-signed-jwt) for the dashboard side.

## FAQ

<AccordionGroup>
  <Accordion title="Auth0 — which claims should I configure in the dashboard?">
    By default, Auth0 puts the user id in `sub` and the email in `email` (when the `email` scope is requested). Set `paths.id = "sub"` and `paths.email = "email"`. With Auth0's namespaced custom-claims pattern, use the namespaced paths instead.
  </Accordion>

  <Accordion title="Clerk — same?">
    Clerk puts the user id in `sub`. Email needs to be added via a Clerk session token template — Clerk doesn't include it by default. Either add `email` to the template, or configure `paths.email` to the metadata path you use.
  </Accordion>

  <Accordion title="Supabase Auth — anonymous users?">
    Supabase Auth supports anonymous users with a stable `user.id` and a valid JWT. `PubliclySignedJwt` works for them; bridge to a real identity later if your campaigns expect it.
  </Accordion>

  <Accordion title="`'none'` safe on staging?">
    Only if staging is behind your VPN / SSO and not customer-facing. The threat model with `'none'` is "anyone with the API key plus a `userId` can read that user's inbox" — fine inside a controlled environment, never on the open internet.
  </Accordion>

  <Accordion title="JWT works locally, fails on prod — what changed?">
    Cross-environment IDP config. Your dev environment is probably wired to dev IDP credentials and a dev JWKS URL; prod needs the prod equivalent. Compare the dashboard auth config side-by-side; most "works on dev only" cases trace to one stale field.
  </Accordion>

  <Accordion title="User has the bell but no notifications — auth or audience?">
    `state.isReady === true` means auth succeeded. If `unreadCount` is 0, the auth is fine but no message reached this `userId`. Check that your campaign's orchestrator emits this exact `userId` as a recipient identifier — most "empty bell" cases are auth working + recipient mismatch.
  </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="Backend tokens" icon="lock" href="/docs/sdks/authentication/backend-tokens">
    `client.generateHashedToken` end-to-end.
  </Card>

  <Card title="Firebase auth" icon="fire" href="/docs/sdks/authentication/firebase">
    Pass a Firebase ID token to the widget.
  </Card>

  <Card title="Publicly-signed JWT" icon="shield" href="/docs/sdks/authentication/publicly-signed-jwt">
    Auth0 / Clerk / Cognito / Supabase setup.
  </Card>
</CardGroup>
