# Token errors

App with login: the widget cannot verify the signed client token.

## Symptom

The site uses **App with login**. The widget is on the page, and sending or opening it says "Could not verify your identity. Refresh the page and try again." The API answer is [MDF-AUTH-001](https://www.modifee.com/docs/errors/MDF-AUTH-001), "You need to sign in."

The token is `base64url` JSON (`email`, `name`, `exp`) plus a dot plus `base64url` HMAC-SHA256 of that payload, signed with `MODIFEE_SECRET`. `exp` is a unix time, 24 hours ahead when you use the install snippet.

## Causes

### `data-token` is empty

**Confirm.** View source on the signed-in page. The script has `data-project` and `data-token=""`, or no `data-token`. The console says "Modifee: data-project and data-token are required". For **App with login**, the button does not mount without a token.

**Fix.** Compute the token on the server for the signed-in user and set `data-token` on that response. Never send `MODIFEE_SECRET` to the browser. See the install page for your stack.

### The signature does not match

Modifee decrypts the current project key and checks the HMAC. A mismatch throws "Invalid client token", which the widget shows as the identity sentence above.

**Confirm.** The token is present and well formed, and **Signing secret** was regenerated, or the server is signing with a different value than the one in the **MODIFEE_SECRET** block.

Three usual mismatches:

- The server still has the previous secret. Regenerating the key invalidates every token signed with the old one. The line "MODIFEE_SECRET set on Vercel ✓" only means the new value is stored. The running deployment keeps the old value until it is redeployed. See [Secret and redeploy](https://www.modifee.com/docs/troubleshooting/secret-and-redeploy).
- Production and Preview hold different values. Modifee writes both targets together. A manual edit on one target, or a preview deployment from before the push, signs with the other secret.
- The token was signed with a secret from another project.

**Fix.** Copy the current **MODIFEE_SECRET**, set it on the server that signs the token, redeploy production and preview, then load the page again so a new token is issued.

### The token is expired

**Confirm.** Decode the payload. `exp` is less than or equal to the current unix time. The snippet sets `exp` to now plus 86400 seconds. The widget shows the same identity sentence.

**Fix.** Render a new token on each request. Do not cache the HTML that contains it.

### The signing server's clock is ahead

Modifee compares `exp` to its own clock. There is no grace period. If the server that signs the token is ahead of real time, `exp` can already be in the past when the browser sends it.

**Confirm.** Decode `exp` and compare it to the current unix time on a clock you trust. The token fails as soon as it is issued, and a short delay makes it valid, or the opposite: it lasts far longer than 24 hours when the signing clock is behind.

**Fix.** Sync the signing server with NTP, then issue a new token.

### A cached page served someone else's token

**Confirm.** Two users receive the same `data-token`, or a signed-out user receives a token. The page is statically generated, cached at the CDN, or sent with a public `Cache-Control`. On the App Router, the layout or page that reads the session is missing `export const dynamic = "force-dynamic"`.

**Fix.** Render that page on every request and do not cache it. See the cache warning on the install page for your stack. [MDF-AUTH-001](https://www.modifee.com/docs/errors/MDF-AUTH-001).
