LakeQL
Overview
  • Introduction
Server Setup
  • createApiServer
  • defineConfig
  • Yoga Configuration
Authentication
  • JWT Authentication
  • Permissions
  • Scope Authorization
Schema Builder
  • Builder Configuration
  • Scalar Types
  • Comparison Types
  • Pagination
  • Input Validation
Customization
  • Custom Queries & Mutations
  • Extending Core
  • CORS Configuration
GitHub
LakeQL
  1. API
  2. Authentication
  3. JWT Authentication

On this page

  1. GetUserResolver type
  2. Default behavior
  3. Mock authentication
  4. Custom JWT verification

JWT Authentication

Configure user authentication via JWT tokens or mock authentication for development.

LakeQL uses JWT-based authentication to identify the current user on each request. The getUser resolver extracts user information from the Authorization header and makes it available in the GraphQL context.

GetUserResolver type #

1
2
3
4
type GetUserResolver = (
  req: Request
) => Promise<JWTPayload | null | undefined> | JWTPayload | null | undefined

Returning null or undefined means the request is unauthenticated. The JWTPayload type extends jose's JWTPayload with an additional userName field:

1
2
3
4
5
6
// Extends jose JWTPayload
interface JWTPayload {
  userName: string
  // ...standard JWT claims (iss, sub, aud, exp, etc.)
}

Default behavior #

The built-in getUser resolver supports mock authentication for local development. It does not perform real JWT verification — you must provide a custom resolver for production.

Mock authentication #

Set the following environment variables to enable mock auth:

1
2
3
AUTH_MOCK=true
AUTH_MOCK_TOKEN=my-dev-token

Then pass the token as the Authorization header and the username via x-username:

1
2
3
4
5
6
curl -X POST http://localhost:4000/graphql \
  -H "Authorization: my-dev-token" \
  -H "x-username: developer" \
  -H "Content-Type: application/json" \
  -d '{"query": "{ __typename }"}'

Custom JWT verification #

For production, provide a custom getUser resolver that verifies tokens using your identity provider:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30import type { GetUserResolver } from "@lakeql/api/types"
import { jwtVerify, createRemoteJWKSet } from "jose"

const jwks = createRemoteJWKSet(
  new URL("https://auth.example.com/.well-known/jwks.json")
)

export const getUser: GetUserResolver = async (req) => {
  const authHeader = req.headers.get("authorization")
  if (!authHeader?.startsWith("Bearer ")) {
    return null
  }

  const token = authHeader.slice(7)

  try {
    const { payload } = await jwtVerify(token, jwks, {
      issuer: "https://auth.example.com",
      audience: "lakeql-api",
    })

    return {
      ...payload,
      userName: payload.sub ?? "unknown",
    }
  } catch {
    return null
  }
}

Pass it to defineConfig in your src/config.ts:

1
2
3
4
5
6
7
8
9
10
11
12
import { defineConfig } from "@lakeql/api/config"

import { getUser } from "./auth"
import { allConfigs } from "./config-registry"

export const config = defineConfig({
  allConfigs,
  baseDir: import.meta.dirname,
  getUser,
  schemaPath: "./schemas",
})

The resolved user is available in every GraphQL resolver via context.currentUser.

Previous page

Authentication

Next page

Permissions

src/auth.ts
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
src/config.ts