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

# Identify customers

> Connect a signed-in customer in your app to the same person in Glean Feed with server-signed identity.

Signed identity connects a logged-in customer in your app to the same person in Glean Feed, so they can submit, vote, comment, and react without a separate portal sign-in. Skip it and the SDK continues with anonymous browsing.

<Warning>
  The signature is created on **your server** with the workspace **widget secret**. Never ship the
  secret in an app binary, and never sign identities in the app. The SDK only forwards a signature
  you generate — it has no signing helper by design.
</Warning>

## The flow

1. Your app asks **your backend** for a signature for the current customer.
2. Your app calls `GleanFeed.identify(...)` with that signature.
3. Glean Feed verifies it and opens authenticated views for that customer.

```swift theme={null}
// after the user signs into your app
let signature = try await yourBackend.gleanFeedSignature(userId: user.id, email: user.email)

try await GleanFeed.identify(
  userId: user.id,
  email: user.email,      // optional
  name: user.name,        // optional
  signature: signature
)
```

`identify` throws a typed `GleanFeedError` on failure; handle the error and continue anonymously when appropriate. Call `GleanFeed.logout()` when the customer signs out of your app. It clears Glean Feed identity and stored SDK tokens, not your app's authentication.

## The signature (server-side)

Same contract as the web widget. If the customer has an email, trim and lowercase it, then sign this compact JSON array:

```text theme={null}
["workspace-id","user-123","person@example.com"]
```

If the customer has no email, sign the workspace and user ID:

```text theme={null}
workspace-id:user-123
```

Use HMAC-SHA256 and return the lowercase hex digest.

```ts theme={null}
import { createHmac } from "node:crypto";

// Runs on YOUR server, with your workspace widget secret (never in the app).
function gleanFeedSignature({
  workspaceId,
  userId,
  email,
  widgetSecret,
}: {
  workspaceId: string;
  userId: string;
  email?: string;
  widgetSecret: string;
}) {
  const canonicalEmail = email?.trim().toLowerCase();
  const payload = canonicalEmail
    ? JSON.stringify([workspaceId, userId, canonicalEmail])
    : `${workspaceId}:${userId}`;
  return createHmac("sha256", widgetSecret).update(payload).digest("hex");
}
```

<Note>
  Sign with the same `userId` you pass to `identify`. When email is present, sign its trimmed,
  lowercased form; Glean Feed applies that same canonicalization to the submitted email before
  verification.
</Note>

## Confirm identity

After `identify` returns successfully, present feedback and submit or vote as the test customer. In the Glean Feed dashboard, open the request and confirm the expected customer is attached. Then call `GleanFeed.logout()`, reopen the view, and confirm the SDK returns to signed-out portal behavior.
