Authdog

Job board

Last updated Oct 7, 2026
View as Markdown

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

Clone starters/redwood. SDK reference: RedwoodJS.

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 inside the guarded handler.

What you need

Requirement Detail
Public key pk_... from the console
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:

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

// 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

// 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).