# Clerk on Express

## Env before import

Clerk reads `CLERK_PUBLISHABLE_KEY` and `CLERK_SECRET_KEY` when its modules initialize, not per request. If your `.env` loads after `import { clerkMiddleware } from '@clerk/express'`, the keys are missing and every request fails auth.

Checklist:
- Run Node with `--env-file=.env` so variables exist before any import runs.
- If you use dotenv, the `dotenv.config()` call must be the very first import in the entry file, before any Clerk import.
- Never expose the secret key to the frontend. Express is the backend; the secret stays server-side only.

## Wire-up

```ts
import express from 'express'
import { clerkMiddleware, clerkClient, getAuth } from '@clerk/express'

const app = express()
app.use(clerkMiddleware())
```

`clerkMiddleware()` checks the request's cookies and headers for a session JWT and attaches the Auth object to the request. Mount it before your routes.

## Protect routes with getAuth(req)

```ts
app.get('/protected', async (req, res) => {
  const { isAuthenticated, userId } = getAuth(req)
  if (!isAuthenticated) {
    res.status(401).json({ error: 'Unauthorized' })
    return
  }
  const user = await clerkClient.users.getUser(userId)
  res.json({ user })
})
```

`getAuth()` returns the auth state; it does not throw and does not send the 401 for you. The `if (!isAuthenticated)` check is your code, every route, no exceptions.

Optional but worth it for TypeScript: add `/// [reference types="@clerk/express/env" /]` in a `types/globals.d.ts` file for typed `req.auth` autocompletion.