`@authdog/express` resolves Authdog sessions for Express 4 and 5. It reads a cookie or bearer token, checks it through the environment's OIDC `userinfo` endpoint, and exposes the result to route handlers.

## Install

```package-install
@authdog/express express
```

`@authdog/express` is published on npm. `express` is a peer dependency (`^4.18` or `^5`); `@authdog/node-commons` installs automatically.

## Configure

Create one client with your environment's public key (`pk_...`):

```ts
import express from "express"
import { createAuthdog } from "@authdog/express"

const app = express()
const authdog = createAuthdog({ publicKey: process.env.PK_AUTHDOG! })
```

The key is safe to expose. It is parsed at startup; malformed keys and identity hosts outside the trusted HTTPS allowlist fail immediately.

## Attach the session

Mount `attachSession()` before routes:

```ts
app.use(authdog.attachSession())
```

It prefers the `authdog-session` cookie, then reads `Authorization: Bearer <token>`. A valid token requires a successful `userinfo` response (`meta.code === 200` with a user). Missing, expired, malformed, or unverifiable tokens do not fail the request; they produce:

```ts
{
  token: string | null,
  user: unknown | null,
  isAuthenticated: boolean,
  userInfo?: UserInfoResponse | null,
}
```

`attachSession({ fetchUser: false })` only surfaces the unverified token. It deliberately leaves `user` null and `isAuthenticated` false, so the built-in `requireAuth` rejects the request with 401. Use this option only when separate server-side validation and enforcement replace Authdog's gate.

## Protect a route

`attachSession` only records context. `requireAuth` is the security boundary and returns `401 {"error":"Unauthorized"}` unless `isAuthenticated` is true:

```ts
app.get("/me", authdog.requireAuth, (req, res) => {
  res.json(req.authdog!.user)
})
```

Authentication identifies a caller; it does not authorize actions. Apply your [authorization](/docs/concepts/authorization) checks after `requireAuth`. Client-side checks never protect server routes.

## Sign out

`logout` expires the local cookie and redirects to a sanitized same-origin `redirect_uri`:

```ts
app.get("/logout", authdog.logout)
```

This does not revoke a bearer token or end an upstream identity-provider session.

## Next steps

- [Backend requests](/docs/backend)
- [Fastify](/docs/backend/fastify)
- [Calling the REST API](/docs/api)
