# 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.