The job board keeps listings public. `applications` returns candidates only after `requireAuth`.

Clone [starters/redwood](https://github.com/authdog/samples/tree/main/starters/redwood). SDK reference: [RedwoodJS](/docs/frameworks/redwood).

`initAuthdog()` stores the browser token after a shape check. `requireAuth` on the API side is the identity gate. It does not grant a permission. Apply [authorization](/docs/concepts/authorization) inside the guarded handler.

## What you need

| Requirement | Detail |
| --- | --- |
| Public key | `pk_...` from the [console](https://console.authdog.com) |
| App | This folder is the Authdog slice, not a generated Redwood app. Create the app with `yarn create redwood-app job-board`, copy `web/src/App.tsx` and `api/src/functions/applications.ts` into it, and install `@authdog/redwood` in both workspaces |
| Environment | Set `PK_AUTHDOG` and `REDWOOD_ENV_AUTHDOG_PUBLIC_KEY` to the same public key. Add `REDWOOD_ENV_AUTHDOG_PUBLIC_KEY` to `includeEnvironmentVariables` in `redwood.toml` |
| Secret key | Never put `sk_...` in the web side |
| Return URL | Account portal back to the web app |

## Run

From the Redwood app, not from the starter folder alone:

```bash
yarn rw dev
```

After hosted sign-in, `initAuthdog()` stores the token. `/.redwood/functions/applications` without a bearer returns 401. With `Authorization: Bearer` it returns `app_12` (Support, Northwind) and `app_13` (Billing, Contoso), plus the user from userinfo. Do not wrap `initAuthdog()` in `AuthdogProvider`. That provider strips the token and does not persist it.

## Web callback

```tsx
// web/src/App.tsx
import { useEffect } from "react"
import { initAuthdog } from "@authdog/redwood/web"
import { RedwoodProvider } from "@redwoodjs/web"
import Routes from "src/Routes"

const App = () => {
  useEffect(() => {
    initAuthdog()
  }, [])

  return (
    <RedwoodProvider titleTemplate="%PageTitle | %AppTitle">
      <Routes />
    </RedwoodProvider>
  )
}

export default App
```

## Applications

```ts
// api/src/functions/applications.ts
import { createAuthdog } from "@authdog/redwood/api"
import type { LambdaEvent } from "@authdog/redwood/api"

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

const APPLICATIONS = [
  { id: "app_12", role: "Support", candidate: "Northwind", state: "review" },
  { id: "app_13", role: "Billing", candidate: "Contoso", state: "screen" },
]

export const handler = authdog.requireAuth(async (event: LambdaEvent) => ({
  statusCode: 200,
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    user: event.authdog?.user ?? null,
    applications: APPLICATIONS,
  }),
}))
```

In GraphQL services, resolve the user with `await authdog.getUser(context.event)`.
