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

# Activation & Login

> Expired activation links, "jwt malformed", and login API responses

Find your symptom and open it.

<AccordionGroup>
  <Accordion title="The activation link does not work" icon="envelope-open-text">
    Activation links are short-lived JWTs, so an old link or a second click gives you one of these:

    | Message         | Cause                                                                                                 |
    | --------------- | ----------------------------------------------------------------------------------------------------- |
    | `jwt malformed` | The link is corrupted or truncated, usually a line break inserted by a mail client, or a partial copy |
    | `jwt expired`   | The link passed its lifetime                                                                          |

    <Steps>
      <Step title="Request a new activation email">
        From the login page.
      </Step>

      <Step title="Copy the link, do not retype it">
        And open it in the browser you signed up in.
      </Step>
    </Steps>
  </Accordion>

  <Accordion title="The login API returns 404 or 204" icon="circle-question">
    Neither `/api/health` nor `/auth/me` exists, so if something sent you looking for them, that is
    why they 404.

    What the frontend actually uses is the `auth` cookie in middleware plus `GET /user/self`, which
    comes back empty when you are not signed in. That is the call to watch in the network tab.

    Signed in and `/user/self` still 404s? `NEXT_PUBLIC_BACKEND_URL` does not match the URL your
    browser is using. A mismatched protocol or port breaks the session cookie.
  </Accordion>

  <Accordion title="Self-host: everyone is logged out after a restart" icon="key">
    `JWT_SECRET` signs session tokens, so regenerating it invalidates every existing session.

    <Warning>
      **Everyone signing in again is the mild half.** Unless you have set `ENCRYPTION_KEY`, this same
      value also encrypts your API keys, the OAuth client secrets she issues, saved provider
      credentials and cookie logins such as Skool. Rotating it in that state leaves those rows
      undecryptable, and every connection depending on them has to be set up again by hand.

      Channels connected through a normal OAuth flow survive: their tokens are stored as the network
      returned them.

      **Already rotated and your channels have gone dark? Put the old value back.** That is the whole
      recovery. Then set `ENCRYPTION_KEY` to that old value before rotating anything, which separates
      the two jobs. [Configuration reference](/configuration/reference#encryption-key).
    </Warning>

    Set `JWT_SECRET` once at first deployment. Keep it in a secret manager, a Docker or Kubernetes
    secret, or an untracked `.env` on the host. **Never commit it**, including to a private deploy
    repo: anyone with repo access then holds the signing key for every session token she has ever
    issued.
  </Accordion>

  <Accordion title="Self-host: Origin not allowed" icon="ban">
    The backend builds its CORS allowlist from `FRONTEND_URL`, plus `MAIN_URL` if set. Reach her on
    a hostname or port outside that list and the call is rejected.

    Make `FRONTEND_URL` match the URL you use in the browser exactly, protocol and port included.
  </Accordion>
</AccordionGroup>

## Next steps

<CardGroup cols={2}>
  <Card title="Configuration reference" icon="list" href="/configuration/reference">
    Every variable she reads, including the two above
  </Card>

  <Card title="Email configuration" icon="envelope" href="/configuration/emails">
    Why an activation mail may never have been sent
  </Card>

  <Card title="Domain and HTTPS" icon="lock" href="/installation/domain-and-https">
    Getting the URLs and the cookie domain right
  </Card>

  <Card title="Still stuck?" icon="headset" href="/support">
    What to put in a report so the first reply is the useful one
  </Card>
</CardGroup>
