[
  {
    "path": ".eslintrc.json",
    "content": "{\n  \"extends\": \"next/core-web-vitals\"\n}\n"
  },
  {
    "path": ".github/workflows/coana-analysis.yml",
    "content": "name: Coana Vulnerability Analysis\n\non:\n  schedule:\n    - cron: \"0 3 * * *\" # every day at 3 AM\n  workflow_dispatch:\n    inputs:\n      tags:\n        description: \"Manually run vulnerability analysis\"\n      # Required by the return-dispatch action\n      distinct_id:\n\njobs:\n  coana-vulnerability-analysis:\n    runs-on: ubuntu-latest\n\n    steps:\n      - name: Checkout code\n        uses: actions/checkout@v4\n\n      - name: Run Coana CLI\n        id: coana-cli\n        uses: docker://coana/coana:latest@sha256:74144ed0fc9d7da87dcd45ccd12458cc7c25ad23e47eebd7ceb4860ed396d63e\n        with:\n          args: |\n            coana run . \\\n              --api-key ${{ secrets.COANA_API_KEY }} \\\n              --repo-url https://github.com/${{github.repository}}\n"
  },
  {
    "path": ".github/workflows/coana-guardrail.yml",
    "content": "name: Coana Guardrail\n\non: pull_request\n\njobs:\n  guardrail:\n    runs-on: ubuntu-latest\n\n    steps:\n      - name: Checkout the ${{github.base_ref}} branch\n        uses: actions/checkout@v4\n        with:\n          ref: ${{github.base_ref}} # checkout the base branch (usually master/main).\n\n      - name: Fetch the PR branch\n        run: |\n          git fetch ${{ github.event.pull_request.head.repo.clone_url }} ${{ github.head_ref }}:${{ github.head_ref }} --depth=1\n\n      - name: Get list of changed files relative to the main/master branch\n        id: changed-files\n        run: |\n          echo \"all_changed_files=$(git diff --name-only ${{ github.base_ref }} ${{ github.head_ref }} | tr '\\n' ' ')\" >> $GITHUB_OUTPUT\n\n      - name: Use Node.js 20.x\n        uses: actions/setup-node@v4\n        with:\n          node-version: 20.x\n\n      - name: Run Coana on the ${{github.base_ref}} branch\n        run: |\n          npx @coana-tech/cli run . \\\n            --guardrail-mode \\\n            --api-key ${{ secrets.COANA_API_KEY || 'api-key-unavailable' }} \\\n            -o /tmp/main-branch \\\n            --changed-files ${{ steps.changed-files.outputs.all_changed_files }} \\\n            --lightweight-reachability \\\n\n      # Reset file permissions.\n      # This is necessary because the Coana CLI may add\n      # new files with root ownership since it's using docker.\n      # These files will not be deleted by the clean step in checkout\n      # if the permissions are not reset.\n      - name: Reset file permissions\n        run: sudo chown -R $USER:$USER .\n\n      - name: Checkout the current branch\n        uses: actions/checkout@v4\n        with:\n          clean: true\n\n      - name: Run Coana on the current branch\n        run: |\n          npx @coana-tech/cli run . \\\n            --guardrail-mode \\\n            --api-key ${{ secrets.COANA_API_KEY || 'api-key-unavailable' }} \\\n            -o /tmp/current-branch \\\n            --changed-files ${{ steps.changed-files.outputs.all_changed_files }} \\\n            --lightweight-reachability \\\n\n      - name: Run Report Comparison\n        run: |\n          npx @coana-tech/cli compare-reports \\\n            --api-key ${{ secrets.COANA_API_KEY || 'api-key-unavailable' }} \\\n            /tmp/main-branch/coana-report.json \\\n            /tmp/current-branch/coana-report.json\n        env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n"
  },
  {
    "path": ".gitignore",
    "content": "# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.\n\n# dependencies\n/node_modules\n/.pnp\n.pnp.js\n.yarn/install-state.gz\n\n# testing\n/coverage\n\n# next.js\n/.next/\n/out/\n\n# production\n/build\n\n# misc\n.DS_Store\n*.pem\n\n# debug\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\n\n# local env files\n.env*.local\n\n# vercel\n.vercel\n\n# typescript\n*.tsbuildinfo\nnext-env.d.ts\n"
  },
  {
    "path": ".prettierrc",
    "content": "{\n  \"printWidth\": 100,\n  \"singleQuote\": true\n}\n"
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "content": "# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nWe as members, contributors, and leaders pledge to make participation in our\ncommunity a harassment-free experience for everyone, regardless of age, body\nsize, visible or invisible disability, ethnicity, sex characteristics, gender\nidentity and expression, level of experience, education, socio-economic status,\nnationality, personal appearance, race, religion, or sexual identity\nand orientation.\n\nWe pledge to act and interact in ways that contribute to an open, welcoming,\ndiverse, inclusive, and healthy community.\n\n## Our Standards\n\nExamples of behavior that contributes to a positive environment for our\ncommunity include:\n\n* Demonstrating empathy and kindness toward other people\n* Being respectful of differing opinions, viewpoints, and experiences\n* Giving and gracefully accepting constructive feedback\n* Accepting responsibility and apologizing to those affected by our mistakes,\n  and learning from the experience\n* Focusing on what is best not just for us as individuals, but for the\n  overall community\n\nExamples of unacceptable behavior include:\n\n* The use of sexualized language or imagery, and sexual attention or\n  advances of any kind\n* Trolling, insulting or derogatory comments, and personal or political attacks\n* Public or private harassment\n* Publishing others' private information, such as a physical or email\n  address, without their explicit permission\n* Other conduct which could reasonably be considered inappropriate in a\n  professional setting\n\n## Enforcement Responsibilities\n\nCommunity leaders are responsible for clarifying and enforcing our standards of\nacceptable behavior and will take appropriate and fair corrective action in\nresponse to any behavior that they deem inappropriate, threatening, offensive,\nor harmful.\n\nCommunity leaders have the right and responsibility to remove, edit, or reject\ncomments, commits, code, wiki edits, issues, and other contributions that are\nnot aligned to this Code of Conduct, and will communicate reasons for moderation\ndecisions when appropriate.\n\n## Scope\n\nThis Code of Conduct applies within all community spaces, and also applies when\nan individual is officially representing the community in public spaces.\nExamples of representing our community include using an official e-mail address,\nposting via an official social media account, or acting as an appointed\nrepresentative at an online or offline event.\n\n## Enforcement\n\nInstances of abusive, harassing, or otherwise unacceptable behavior may be\nreported to the community leaders responsible for enforcement at\nsupport@workos.com.\nAll complaints will be reviewed and investigated promptly and fairly.\n\nAll community leaders are obligated to respect the privacy and security of the\nreporter of any incident.\n\n## Enforcement Guidelines\n\nCommunity leaders will follow these Community Impact Guidelines in determining\nthe consequences for any action they deem in violation of this Code of Conduct:\n\n### 1. Correction\n\n**Community Impact**: Use of inappropriate language or other behavior deemed\nunprofessional or unwelcome in the community.\n\n**Consequence**: A private, written warning from community leaders, providing\nclarity around the nature of the violation and an explanation of why the\nbehavior was inappropriate. A public apology may be requested.\n\n### 2. Warning\n\n**Community Impact**: A violation through a single incident or series\nof actions.\n\n**Consequence**: A warning with consequences for continued behavior. No\ninteraction with the people involved, including unsolicited interaction with\nthose enforcing the Code of Conduct, for a specified period of time. This\nincludes avoiding interactions in community spaces as well as external channels\nlike social media. Violating these terms may lead to a temporary or\npermanent ban.\n\n### 3. Temporary Ban\n\n**Community Impact**: A serious violation of community standards, including\nsustained inappropriate behavior.\n\n**Consequence**: A temporary ban from any sort of interaction or public\ncommunication with the community for a specified period of time. No public or\nprivate interaction with the people involved, including unsolicited interaction\nwith those enforcing the Code of Conduct, is allowed during this period.\nViolating these terms may lead to a permanent ban.\n\n### 4. Permanent Ban\n\n**Community Impact**: Demonstrating a pattern of violation of community\nstandards, including sustained inappropriate behavior,  harassment of an\nindividual, or aggression toward or disparagement of classes of individuals.\n\n**Consequence**: A permanent ban from any sort of public interaction within\nthe community.\n\n## Attribution\n\nThis Code of Conduct is adapted from the [Contributor Covenant][homepage],\nversion 2.0, available at\nhttps://www.contributor-covenant.org/version/2/0/code_of_conduct.html.\n\nCommunity Impact Guidelines were inspired by [Mozilla's code of conduct\nenforcement ladder](https://github.com/mozilla/diversity).\n\n[homepage]: https://www.contributor-covenant.org\n\nFor answers to common questions about this code of conduct, see the FAQ at\nhttps://www.contributor-covenant.org/faq. Translations are available at\nhttps://www.contributor-covenant.org/translations.\n"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2023 WorkOS\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "<p align=\"center\">\n    <img src=\"https://github.com/workos/authkit/assets/896475/9fa7a91e-f5a8-4922-96fb-20a7b478d075\" width=\"72\" />\n    <h1 align=\"center\">AuthKit</h1>\n    <p align=\"center\">How to use AuthKit's hosted UI or build your own frontend with the headless User Management APIs</p>    \n    <p align=\"center\"><a href=\"https://workos.com/docs/user-management\">Explore the docs ↗</a></strong></p>    \n</p>\n\n<p align=\"center\">  \n  <img alt=\"Screenshot of hosted UI AuthKit in light mode\" src=\"https://github.com/workos/authkit/assets/108872335/200931ff-51fc-4825-894d-696dd17b88f6\">\n</p>\n\n## Examples\n\nThere are two ways to use AuthKit and this repository contains examples for both:\n\n- [Using AuthKit's hosted UI](./src/app/using-hosted-authkit)\n  This is the fastest way to add authentication to your app with AuthKit and WorkOS User Management. It includes a fully themeable hosted UI that handles all of your authentication flows. When you're ready to go to production you can point it to a custom domain (`auth.yourapp.com`) to match your application.\n- [Using your own custom UI](./src/app/using-your-own-ui)\n  Use all of the features of AuthKit, but build out the UI yourself in your own codebase by integrating directly with the headless WorkOS User Management APIs. Your authentication UI will be self-hosted in your application.\n\n## Prerequisites\n\nYou will need a [WorkOS account](https://dashboard.workos.com/signup).\n\n## Running the example\n\n1. Install dependencies with `npm install` or `yarn install`\n2. Set up your **Environment variables** by signing into your [WorkOS dashboard](https://dashboard.workos.com), navigate to **API Keys** and copy the **Client ID** and the **Secret Key** (API Key).\n   Rename the `.env.local.example` file to `.env.local` and supply your _Client ID_ and _Secret Key_.\n\n   ```bash\n   WORKOS_CLIENT_ID=\"<your Client ID>\"\n   WORKOS_API_KEY=\"<your Secret Key>\"\n   ```\n\n3. Configure redirects in your [WorkOS dashboard](https://dashboard.workos.com), navigate to **Redirects** and add the following urls:\n\n   ```bash\n   http://localhost:3000/using-your-own-ui/sign-in/google-oauth/callback\n   ```\n\n   ```bash\n   http://localhost:3000/using-your-own-ui/sign-in/microsoft-oauth/callback\n   ```\n\n   ```bash\n   http://localhost:3000/using-your-own-ui/sign-in/github-oauth/callback\n   ```\n\n   ```bash\n   http://localhost:3000/using-your-own-ui/sign-in/sso/callback\n   ```\n\n   ```bash\n   http://localhost:3000/using-hosted-authkit/basic/callback\n   ```\n\n   ```bash\n   http://localhost:3000/using-hosted-authkit/with-session/callback\n   ```\n\n   ```bash\n   http://localhost:3000/using-hosted-authkit/with-nextjs/callback\n   ```\n\n4. Run the example with `npm run dev` or `yarn dev` and navigate to http://localhost:3000\n"
  },
  {
    "path": "context7.json",
    "content": "{\n  \"url\": \"https://context7.com/workos/authkit\",\n  \"public_key\": \"pk_q7NnKuFFXMWA7WnmjMHQU\"\n}"
  },
  {
    "path": "next.config.js",
    "content": "/** @type {import('next').NextConfig} */\nconst nextConfig = {}\n\nmodule.exports = nextConfig\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"authkit\",\n  \"version\": \"0.1.0\",\n  \"private\": true,\n  \"scripts\": {\n    \"dev\": \"next dev\",\n    \"build\": \"next build\",\n    \"start\": \"next start\",\n    \"lint\": \"next lint\"\n  },\n  \"dependencies\": {\n    \"@workos-inc/authkit-nextjs\": \"0.4.2\",\n    \"@workos-inc/node\": \"^6.7.0\",\n    \"jose\": \"^5.2.3\",\n    \"next\": \"14.1.4\",\n    \"react\": \"^18\",\n    \"react-dom\": \"^18\"\n  },\n  \"devDependencies\": {\n    \"@types/node\": \"^20\",\n    \"@types/react\": \"^18\",\n    \"@types/react-dom\": \"^18\",\n    \"eslint\": \"^8\",\n    \"eslint-config-next\": \"14.1.4\",\n    \"typescript\": \"^5\"\n  }\n}\n"
  },
  {
    "path": "src/app/back-link.tsx",
    "content": "'use client';\n\nimport Link from 'next/link';\nimport { usePathname } from 'next/navigation';\n\nexport default function BackLink() {\n  const pathname = usePathname();\n  const segments = pathname.split('/').filter(Boolean);\n  if (segments.length === 0) return null;\n  if (segments.length === 1) return <Link href=\"/\">Home</Link>;\n  return <Link href={`/${segments[0]}`}>Examples</Link>;\n}\n"
  },
  {
    "path": "src/app/globals.css",
    "content": "::selection {\n  background-color: #003eff3e;\n}\n\nbody {\n  margin: 0;\n  font-size: 20px;\n}\n\na {\n  color: black;\n  text-decoration-thickness: 1px;\n  text-underline-offset: 2px;\n  text-decoration-color: #888;\n}\n\n/* back link */\nbody > a {\n  position: fixed;\n  top: 12px;\n  left: 12px;\n}\n\nmain {\n  display: flex;\n  flex-direction: column;\n  align-items: center;\n  justify-content: center;\n  min-height: 100vh;\n  box-sizing: border-box;\n  padding-top: 48px;\n}\n\nh1 {\n  text-align: center;\n  margin: 0;\n  margin-top: auto;\n  margin-bottom: 24px;\n}\nh1:has(+ h2) {\n  margin-bottom: 8px;\n}\n\nh2 {\n  text-align: center;\n  margin: 0;\n  margin-bottom: 32px;\n}\n\nh2:has(+ ul) {\n  margin-top: 24px;\n  margin-bottom: 8px;\n}\n\nmain > form {\n  display: flex;\n  flex-direction: column;\n  width: 400px;\n  gap: 24px;\n  margin-bottom: auto;\n}\n\n/* field (label + input) */\nform > div {\n  display: flex;\n  flex-direction: column;\n  gap: 8px;\n}\n\nlabel {\n  font-size: 16px;\n  font-weight: bold;\n}\n\ninput {\n  width: 100%;\n  box-sizing: border-box;\n  border: 2px solid black;\n  border-radius: 4px;\n  font-size: 20px;\n  font-family: inherit;\n  height: 48px;\n  padding: 0 12px;\n}\n\nbutton,\n:where(main, form) > a {\n  display: flex;\n  align-items: center;\n  justify-content: center;\n  width: 100%;\n  box-sizing: border-box;\n  background-color: black;\n  color: white;\n  border-radius: 4px;\n  font-size: 20px;\n  height: 48px;\n  font-family: inherit;\n  border: 0;\n  padding: 0 12px;\n  margin: 8px 0;\n  cursor: pointer;\n  text-decoration: none;\n}\nbutton:active,\n:where(main, form) > a:active {\n  background-color: #333;\n}\nmain > a {\n  width: 400px;\n  margin-bottom: auto;\n}\n\npre {\n  font-size: 16px;\n  box-sizing: border-box;\n  min-height: 250px;\n  height: auto;\n  overflow: auto;\n  width: 100vw;\n  margin: 0;\n  margin-top: 40px;\n  bottom: 0;\n  left: 0;\n  right: 0;\n  padding: 20px;\n  background-color: #fafafa;\n  border-top: 1px solid #eee;\n}\n\n/* lists for index pages */\nul {\n  text-align: center;\n  list-style-type: none;\n  margin: 0;\n  padding-left: 0;\n}\n\nh2 + ul:not(:last-child) {\n  margin-bottom: 36px;\n}\n\nh1 + ul:last-child,\nh2 + ul:last-child {\n  margin-bottom: auto;\n  padding-bottom: 48px;\n}\n\nli {\n  margin: 8px 0;\n}\n\n/* table for users table page */\nmain:has(table) h1 {\n  margin-top: 0;\n}\n\ntable {\n  width: 100%;\n  border-collapse: collapse;\n}\nth,\ntd {\n  text-align: left;\n  padding: 12px 24px;\n  border-bottom: 1px solid black;\n}\ntable + nav {\n  box-sizing: border-box;\n  display: flex;\n  align-items: center;\n  justify-content: space-between;\n  padding: 24px;\n  width: 100%;\n  gap: 24px;\n  margin-bottom: auto;\n  color: #888;\n}\ntable button {\n  margin: 0;\n}\n"
  },
  {
    "path": "src/app/layout.tsx",
    "content": "import type { Metadata } from 'next';\nimport { Inter } from 'next/font/google';\n\nimport './globals.css';\nimport BackLink from './back-link';\n\nconst inter = Inter({ subsets: ['latin'] });\n\nexport const metadata: Metadata = {\n  title: 'AuthKit',\n  description: 'A collection of examples for AuthKit',\n};\n\nexport default function RootLayout({ children }: { children: React.ReactNode }) {\n  return (\n    <html lang=\"en\">\n      <body className={inter.className}>\n        <BackLink />\n        {children}\n      </body>\n    </html>\n  );\n}\n"
  },
  {
    "path": "src/app/page.tsx",
    "content": "import Link from 'next/link';\n\nexport default function Home() {\n  return (\n    <main>\n      <h1>Examples</h1>\n      <ul>\n        <li>\n          <Link href=\"/using-your-own-ui\">Using your own UI</Link>\n        </li>\n        <li>\n          <Link href=\"/using-hosted-authkit\">Using hosted AuthKit</Link>\n        </li>\n      </ul>\n    </main>\n  );\n}\n"
  },
  {
    "path": "src/app/using-hosted-authkit/README.md",
    "content": "<p align=\"center\">\n    <img src=\"https://github.com/workos/authkit/assets/896475/9fa7a91e-f5a8-4922-96fb-20a7b478d075\" width=\"72\" />\n    <h1 align=\"center\">Using AuthKit's hosted UI</h1>\n    <p align=\"center\">How to use AuthKit with themeable hosted UI</p>\n    <p align=\"center\"><strong><a href=\"#examples\">View the examples</a></strong>&nbsp;&nbsp;·&nbsp;&nbsp;<strong><a href=\"https://workos.com/docs/user-management\">Explore the docs ↗</a></strong></p>\n    <br><br><br>\n</p>\n\n## Setup\n\nFirst, ensure you have set up the [environment variables](/#environment-variables) and [redirects](/#redirects).\n\nFor each example, you will need to ensure the applicable authentication method is enabled in your WorkOS dashboard. To do so navigate to **Authentication** and edit the applicable authentication method and ensure it is set to **Enabled**.\n\nFor the Google OAuth and Microsoft OAuth examples, WorkOS provides demo app credentials to use in your WorkOS staging environment. This allows you to test these authentication flows without having to set up your own OAuth apps.\n\nIn order to test Single Sign-On, you will need to create an organization in your WorkOS dashboard. Navigate to **Organizations** and then **Create organization**. Enter a name for this organization, and optionally add a domain that the members will use to sign in. You will also need to create a Single Sign-On connection in the WorkOS dashboard for this organization. On this organization's detail page, navigate to the authentication section, find **Single Sign-On**. For the purposes of this example, we will use the **Configure Manually** feature to create a new connection. This requires you to have access to an identity provider (IdP) for testing such as Entra ID (Azure AD), Google Workspace, or Okta.\n\n## Examples\n\n- [Basic authentication](./basic/page.tsx). How to use AuthKit's hosted UI with any authentication method (Email + Password, Magic Auth, Google OAuth, Microsoft OAuth, and Single Sign-On).\n- [Using the authkit-nextjs library](./with-nextjs/page.tsx). How to use AuthKit's hosted UI in Next.js with managed client-side sessions and impersonation.\n- [With client-side sessions](./with-session/page.tsx). How to use AuthKit's hosted UI and manage sessions client-side using JavaScript Web Tokens (JWTs).\n\n### Next.js\n\nFor the `authkit-nextjs` example, you'll need to add the following to your environment variables:\n\n```bash\n# Needed for authkit-nextjs library example, defined in WorkOS dashboard\nWORKOS_REDIRECT_URI=\n\n# Needed for authkit-nextjs library example. Must be at least 32 characters long\nWORKOS_COOKIE_PASSWORD=\n```\n\nTo generate a secure cookie password, you can use the [1Password generator](https://1password.com/password-generator/) or use the `openssl` library to generate a strong password on the command line:\n\n```bash\nopenssl rand -base64 24\n```\n\n### Sessions\n\nFor the example with client-side sessions, you will need to add a JWT secret as an environment variable. It can be any random base64 string for testing locally. You can use the `openssl` library to easily generate a key.\n\n```bash\nopenssl rand -base64 32\n```\n\nAnd update the `.env.local` file:\n\n```bash\n# ...\nJWT_SECRET_KEY=\"<your JTW secret>\"\n```\n"
  },
  {
    "path": "src/app/using-hosted-authkit/basic/callback/route.ts",
    "content": "import { WorkOS } from '@workos-inc/node';\nimport { redirect } from 'next/navigation';\n\n// This is a Next.js Route Handler.\n//\n// If your application is a single page app (SPA) with a separate backend you will need to:\n// - create a backend endpoint to handle the request\n// - adapt the code below in your endpoint\n//\n// Please also note that for the sake of simplicity, we directly return the user here in the query string.\n// In a real application, you would probably store the user in a token (JWT)\n// and store that token in your DB or use cookies (See `with-session` example for more details).\n\nconst workos = new WorkOS(process.env.WORKOS_API_KEY);\n\nexport async function GET(request: Request) {\n  const code = new URL(request.url).searchParams.get('code') || '';\n\n  let response;\n\n  try {\n    response = await workos.userManagement.authenticateWithCode({\n      clientId: process.env.WORKOS_CLIENT_ID || '',\n      code,\n    });\n  } catch (error) {\n    response = error;\n  }\n\n  if (response) {\n    redirect(\n      `http://localhost:3000/using-hosted-authkit/basic?response=${JSON.stringify(response)}`\n    );\n  }\n}\n"
  },
  {
    "path": "src/app/using-hosted-authkit/basic/page.tsx",
    "content": "import { WorkOS } from '@workos-inc/node';\n\n// This example uses Next.js with React Server Components.\n// Because this page is an RSC, the code stays on the server, which allows\n// us to use the WorkOS Node SDK without exposing our API key to the client.\n//\n// If your application is a single page app (SPA), you will need to:\n// - create a form that can POST to an endpoint in your backend\n// - call the `getAuthorizationURL` method in that endpoint\n// - redirect the user to the returned URL\n\nconst workos = new WorkOS(process.env.WORKOS_API_KEY);\n\nexport default function Basic({\n  searchParams,\n}: {\n  searchParams: { [key: string]: string | string[] | undefined };\n}) {\n  const authKitUrl = workos.userManagement.getAuthorizationUrl({\n    clientId: process.env.WORKOS_CLIENT_ID || '',\n    provider: 'authkit',\n    redirectUri: 'http://localhost:3000/using-hosted-authkit/basic/callback',\n  });\n\n  const result = JSON.parse(String(searchParams.response ?? '{ \"error\": null }'));\n\n  return (\n    <main>\n      <h1>Using hosted AuthKit</h1>\n      <h2>Basic example</h2>\n      <a href={authKitUrl}>Sign-in with AuthKit</a>\n      <pre>{JSON.stringify(result, null, 2)}</pre>\n    </main>\n  );\n}\n"
  },
  {
    "path": "src/app/using-hosted-authkit/page.tsx",
    "content": "import Link from 'next/link';\n\nexport default function UsingHostedAuthKit() {\n  return (\n    <main>\n      <h1>Using hosted AuthKit</h1>\n      <ul>\n        <li>\n          <Link href=\"/using-hosted-authkit/basic\">Basic example</Link>\n        </li>\n        <li>\n          <Link href=\"/using-hosted-authkit/with-nextjs\">With Next.js library</Link>\n        </li>\n        <li>\n          <Link href=\"/using-hosted-authkit/with-session\">With session</Link>\n        </li>\n      </ul>\n    </main>\n  );\n}\n"
  },
  {
    "path": "src/app/using-hosted-authkit/with-nextjs/callback/route.ts",
    "content": "import { handleAuth } from '@workos-inc/authkit-nextjs';\n\nexport const GET = handleAuth({ returnPathname: '/using-hosted-authkit/with-nextjs/' });\n"
  },
  {
    "path": "src/app/using-hosted-authkit/with-nextjs/page.tsx",
    "content": "import { getSignInUrl, getUser, signOut } from '@workos-inc/authkit-nextjs';\n\nexport default async function WithNextjs() {\n  // Retrieves the user from the session or returns `null` if no user is signed in\n  const { user } = await getUser();\n\n  // Get the URL to redirect the user to AuthKit to sign in\n  const signInUrl = await getSignInUrl();\n\n  return (\n    <main>\n      <h1>Using hosted AuthKit</h1>\n      <h2>With Next.js library</h2>\n      {user ? (\n        <>\n          <p>Welcome back {user?.firstName && `, ${user?.firstName}`}</p>\n          <form\n            action={async () => {\n              'use server';\n              await signOut();\n            }}\n          >\n            <button type=\"submit\">Sign out</button>\n          </form>\n        </>\n      ) : (\n        <a href={signInUrl}>Sign in</a>\n      )}\n      <pre>{JSON.stringify(user, null, 2)}</pre>\n    </main>\n  );\n}\n"
  },
  {
    "path": "src/app/using-hosted-authkit/with-session/auth.ts",
    "content": "import { cookies } from 'next/headers';\nimport { redirect } from 'next/navigation';\nimport { jwtVerify } from 'jose';\nimport type { User } from '@workos-inc/node';\n\nexport function getJwtSecretKey() {\n  const secret = process.env.JWT_SECRET_KEY;\n\n  if (!secret) {\n    throw new Error('JWT_SECRET_KEY is not set');\n  }\n\n  return new Uint8Array(Buffer.from(secret, 'base64'));\n}\n\nexport async function verifyJwtToken(token: string) {\n  try {\n    const { payload } = await jwtVerify(token, getJwtSecretKey());\n    return payload;\n  } catch (error) {\n    return null;\n  }\n}\n\n// Verify the JWT and return the user\nexport async function getUser(): Promise<{\n  isAuthenticated: boolean;\n  user?: User | null;\n}> {\n  const token = cookies().get('token')?.value;\n\n  if (token) {\n    const verifiedToken = await verifyJwtToken(token);\n    if (verifiedToken) {\n      return {\n        isAuthenticated: true,\n        user: verifiedToken.user as User | null,\n      };\n    }\n  }\n\n  return { isAuthenticated: false };\n}\n\n// Clear the session and redirect to the home page\nexport async function signOut() {\n  cookies().delete('token');\n  redirect('/using-hosted-authkit/with-session');\n}\n"
  },
  {
    "path": "src/app/using-hosted-authkit/with-session/callback/route.ts",
    "content": "import { WorkOS } from '@workos-inc/node';\nimport { NextResponse } from 'next/server';\nimport { SignJWT } from 'jose';\nimport { getJwtSecretKey } from '../auth';\n\n// This is a Next.js Route Handler.\n//\n// If your application is a single page app (SPA) with a separate backend you will need to:\n// - create a backend endpoint to handle the request\n// - adapt the code below in your endpoint\n\nconst workos = new WorkOS(process.env.WORKOS_API_KEY);\n\nexport async function GET(request: Request) {\n  const url = new URL(request.url);\n  const code = url.searchParams.get('code') || '';\n\n  try {\n    const { user } = await workos.userManagement.authenticateWithCode({\n      clientId: process.env.WORKOS_CLIENT_ID || '',\n      code,\n    });\n\n    // Create a JWT with the user's information\n    // Here you might lookup and retrieve user details from your database\n    const token = await new SignJWT({ user })\n      .setProtectedHeader({ alg: 'HS256', typ: 'JWT' })\n      .setIssuedAt()\n      .setExpirationTime('1h')\n      .sign(getJwtSecretKey());\n\n    // Cleanup params\n    url.searchParams.delete('code');\n\n    // Store the session and redirect to the application\n    url.pathname = '/using-hosted-authkit/with-session';\n    const response = NextResponse.redirect(url);\n\n    response.cookies.set({\n      name: 'token',\n      value: token,\n      httpOnly: true,\n      path: '/',\n      secure: true,\n      sameSite: 'lax',\n    });\n\n    return response;\n  } catch (error) {\n    return NextResponse.json(error);\n  }\n}\n"
  },
  {
    "path": "src/app/using-hosted-authkit/with-session/page.tsx",
    "content": "import { WorkOS } from '@workos-inc/node';\nimport { getUser, signOut } from './auth';\n\n// This example uses Next.js with React Server Components.\n// Because this page is an RSC, the code stays on the server, which allows\n// us to use the WorkOS Node SDK without exposing our API key to the client.\n//\n// If your application is a single page app (SPA), you will need to:\n// - create a form that can POST to an endpoint in your backend\n// - call the `getAuthorizationURL` method in that endpoint\n// - redirect the user to the returned URL\n\nconst workos = new WorkOS(process.env.WORKOS_API_KEY);\n\nexport default async function WithSession() {\n  const { isAuthenticated, user } = await getUser();\n\n  const authKitUrl = workos.userManagement.getAuthorizationUrl({\n    clientId: process.env.WORKOS_CLIENT_ID || '',\n    provider: 'authkit',\n    redirectUri: 'http://localhost:3000/using-hosted-authkit/with-session/callback',\n  });\n\n  return (\n    <main>\n      <h1>With session</h1>\n\n      {isAuthenticated ? (\n        <>\n          <h2>Welcome back{user?.firstName && `, ${user?.firstName}`}</h2>\n          <p>You are now authenticated into the application.</p>\n\n          <form\n            action={async () => {\n              'use server';\n              await signOut();\n            }}\n          >\n            <button type=\"submit\">Sign-out</button>\n          </form>\n        </>\n      ) : (\n        <>\n          <h2>Sign-in</h2>\n          <p>Sign-in to view your account details</p>\n          <a href={authKitUrl}>Sign-in</a>\n        </>\n      )}\n\n      <pre>{JSON.stringify({ user }, null, 2)}</pre>\n    </main>\n  );\n}\n"
  },
  {
    "path": "src/app/using-your-own-ui/README.md",
    "content": "<p align=\"center\">\n    <img src=\"https://github.com/workos/authkit/assets/896475/9fa7a91e-f5a8-4922-96fb-20a7b478d075\" width=\"72\" />\n    <h1 align=\"center\">Using AuthKit with your own UI</h1>\n    <p align=\"center\">How to use AuthKit with your own frontend using headless User Management APIs</p>\n    <p align=\"center\"><strong><a href=\"#examples\">View the examples</a></strong>&nbsp;&nbsp;·&nbsp;&nbsp;<strong><a href=\"https://workos.com/docs/user-management\">Explore the docs ↗</a></strong></p>\n    <br><br><br>\n</p>\n\n## Setup\n\nFirst, ensure you have set up the [environment variables](/#environment-variables) and [redirects](/#redirects).\n\nFor each example, you will need to ensure the applicable authentication method is enabled in your WorkOS dashboard. To do so navigate to **Authentication** and edit the applicable authentication method and ensure it is set to **Enabled**.\n\nFor the Google OAuth and Microsoft OAuth examples, WorkOS provides demo app credentials to use in your WorkOS staging environment. This allows you to test these authentication flows without having to set up your own OAuth apps.\n\n## Examples\n\n### Sign-up\n\n- [Email + Password](./sign-up/email-password/page.tsx)\n- [Magic Auth](./sign-up/magic-auth/page.tsx)\n\n### Sign-in\n\n- [Email + Password](./sign-in/email-password/page.tsx)\n- [Magic Auth](./sign-in/magic-auth/page.tsx)\n- [Google OAuth](./sign-in/google-oauth/page.tsx)\n- [Microsoft OAuth](./sign-in/microsoft-oauth/page.tsx)\n- [Single Sign-On](./sign-in/sso/page.tsx)\n\nFor the Single Sign-On example, you will need to create an organization in your WorkOS dashboard. Navigate to **Organizations** and then **Create organization**. Enter a name for this organization, and optionally add a domain that the members will use to sign in. You will also need to create a Single Sign-On connection in the WorkOS dashboard for this organization. On this organization's detail page, navigate to the authentication section, find **Single Sign-On**. For the purposes of this example, we will use the **Configure Manually** feature to create a new connection. This requires you to have access to an identity provider (IdP) for testing such as Entra ID (Azure AD), Google Workspace, or Okta.\n\nYou will also need to copy the **Organization ID** from the organization you created with the active Single Sign-On connection. This is located below the organization's name on its detail page (beginning with `org_`). Copy it and add it to your `.env.local` file.\n\n```bash\nSSO_ENABLED_ORGANIZATION_ID=\"<your Organization ID>\"\n```\n\n### Other\n\n- [Multi-Factor Auth](./mfa/page.tsx)\n- [Verify email](./verify-email/page.tsx)\n- [Reset password](./reset-password/page.tsx)\n- [Users table](./users-table/page.tsx)\n- [Update user](./update-user/page.tsx)\n"
  },
  {
    "path": "src/app/using-your-own-ui/mfa/mfa.ts",
    "content": "'use server';\n\n// These are Next.js server actions.\n//\n// If your application is a single page app (SPA) with a separate backend you will need to:\n// - create a backend endpoint to handle each request\n// - adapt the code below in each of those endpoints\n//\n// Please also note that for the sake of simplicity, we return all errors here.\n// In a real application, you should pay attention to which errors make it\n// to the client for security reasons.\n\nimport { WorkOS } from '@workos-inc/node';\n\nconst workos = new WorkOS(process.env.WORKOS_API_KEY);\n\nexport async function signIn(prevState: any, formData: FormData): Promise<SignInResponse> {\n  try {\n    // For the sake of simplicity, we directly return the user here.\n    // In a real application, you would probably store the user in a token (JWT)\n    // and store that token in your DB or use cookies.\n    return await workos.userManagement.authenticateWithPassword({\n      clientId: process.env.WORKOS_CLIENT_ID || '',\n      email: String(formData.get('email')),\n      password: String(formData.get('password')),\n    });\n  } catch (error) {\n    const err = JSON.parse(JSON.stringify(error));\n\n    if (err.rawData.code === 'mfa_enrollment') {\n      const { authenticationFactor, authenticationChallenge } =\n        await workos.userManagement.enrollAuthFactor({\n          userId: err.rawData.user.id,\n          type: 'totp',\n          totpIssuer: 'WorkOS',\n          totpUser: err.rawData.user.email,\n        });\n      return {\n        authenticationFactor,\n        authenticationChallenge,\n        pendingAuthenticationToken: err.rawData.pending_authentication_token,\n      };\n    }\n\n    if (err.rawData.code === 'mfa_challenge') {\n      const challenge = await workos.mfa.challengeFactor({\n        authenticationFactorId: err.rawData.authentication_factors[0].id,\n      });\n      return {\n        authenticationChallenge: challenge,\n        pendingAuthenticationToken: err.rawData.pending_authentication_token,\n      };\n    }\n\n    return { error: err };\n  }\n}\n\nexport async function verifyTotp(prevState: any, formData: FormData) {\n  try {\n    // For the sake of simplicity, we directly return the user here.\n    // In a real application, you would probably store the user in a token (JWT)\n    // and store that token in your DB or use cookies.\n    return await workos.userManagement.authenticateWithTotp({\n      clientId: process.env.WORKOS_CLIENT_ID || '',\n      authenticationChallengeId: String(formData.get('authenticationChallengeId')),\n      pendingAuthenticationToken: String(formData.get('pendingAuthenticationToken')),\n      code: String(formData.get('code')),\n    });\n  } catch (error) {\n    return { error: JSON.parse(JSON.stringify(error)) };\n  }\n}\n\ntype UnpackPromise<T> = T extends Promise<infer U> ? U : T;\ntype AuthenticateResponse = UnpackPromise<\n  ReturnType<typeof workos.userManagement.authenticateWithPassword>\n>;\ntype EnrollResponse = UnpackPromise<ReturnType<typeof workos.userManagement.enrollAuthFactor>>;\ntype SignInResponse =\n  | AuthenticateResponse\n  | {\n      authenticationFactor?: EnrollResponse['authenticationFactor'];\n      authenticationChallenge: EnrollResponse['authenticationChallenge'];\n      pendingAuthenticationToken: string;\n    }\n  | { error: any };\n"
  },
  {
    "path": "src/app/using-your-own-ui/mfa/page.tsx",
    "content": "'use client';\n\nimport { useFormState } from 'react-dom';\nimport { signIn, verifyTotp } from './mfa';\nimport Image from 'next/image';\n\nexport default function Mfa() {\n  // This example uses Next.js server actions to call functions on the server side.\n  //\n  // If your application is a single page app (SPA), you will need to:\n  // - handle the form submission in `<form onSubmit>`\n  // - make an API call to your backend (e.g using `fetch`)\n  const [signInState, signInAction] = useFormState(signIn, { error: null });\n  const [verifyState, verifyAction] = useFormState(verifyTotp, { error: null });\n\n  if (!('authenticationChallenge' in signInState) || 'user' in signInState) {\n    return (\n      <main key=\"sign-in\">\n        <h1>Multi-Factor Auth</h1>\n        <h2>Sign-in</h2>\n\n        <form action={signInAction}>\n          <div>\n            <label htmlFor=\"email\">Email</label>\n            <input\n              type=\"email\"\n              name=\"email\"\n              id=\"email\"\n              autoCapitalize=\"off\"\n              autoComplete=\"username\"\n              autoFocus\n              required\n            />\n          </div>\n\n          <div>\n            <label htmlFor=\"password\">Password</label>\n            <input\n              type=\"password\"\n              name=\"password\"\n              id=\"password\"\n              autoCapitalize=\"off\"\n              autoComplete=\"current-password\"\n              required\n            />\n          </div>\n\n          <button type=\"submit\">Sign-in</button>\n        </form>\n\n        <pre>{JSON.stringify(signInState, null, 2)}</pre>\n      </main>\n    );\n  }\n\n  return (\n    <main key=\"mfa\">\n      <h1>Multi-Factor Auth</h1>\n\n      {signInState.authenticationFactor ? (\n        <>\n          <h2>Enroll</h2>\n          <p>Scan the QR code</p>\n          <Image\n            src={signInState.authenticationFactor.totp.qrCode}\n            width=\"160\"\n            height=\"160\"\n            alt=\"QR code\"\n          />\n          <p>then</p>\n        </>\n      ) : (\n        <h2>Verify</h2>\n      )}\n\n      <form action={verifyAction}>\n        <div>\n          <label htmlFor=\"code\">Enter the code from your app</label>\n          <input\n            type=\"text\"\n            name=\"code\"\n            id=\"code\"\n            inputMode=\"numeric\"\n            autoComplete=\"one-time-code\"\n            pattern=\"^\\d{6}$\"\n            autoFocus\n            required\n          />\n        </div>\n\n        <input\n          type=\"hidden\"\n          name=\"authenticationChallengeId\"\n          value={signInState.authenticationChallenge.id}\n        />\n\n        <input\n          type=\"hidden\"\n          name=\"pendingAuthenticationToken\"\n          value={signInState.pendingAuthenticationToken}\n        />\n\n        <button type=\"submit\">Continue</button>\n      </form>\n\n      <pre>{JSON.stringify(verifyState, null, 2)}</pre>\n    </main>\n  );\n}\n"
  },
  {
    "path": "src/app/using-your-own-ui/page.tsx",
    "content": "import Link from 'next/link';\n\nexport default function UsingYourOwnUi() {\n  return (\n    <main>\n      <h1>Using your own UI</h1>\n\n      <h2>Sign-up</h2>\n      <ul>\n        <li>\n          <Link href=\"/using-your-own-ui/sign-up/email-password\">Email + Password</Link>\n        </li>\n        <li>\n          <Link href=\"/using-your-own-ui/sign-up/magic-auth\">Magic Auth</Link>\n        </li>\n      </ul>\n\n      <h2>Sign-in</h2>\n      <ul>\n        <li>\n          <Link href=\"/using-your-own-ui/sign-in/email-password\">Email + Password</Link>\n        </li>\n        <li>\n          <Link href=\"/using-your-own-ui/sign-in/magic-auth\">Magic Auth</Link>\n        </li>\n        <li>\n          <Link href=\"/using-your-own-ui/sign-in/github-oauth\">GitHub OAuth</Link>\n        </li>\n        <li>\n          <Link href=\"/using-your-own-ui/sign-in/google-oauth\">Google OAuth</Link>\n        </li>\n        <li>\n          <Link href=\"/using-your-own-ui/sign-in/microsoft-oauth\">Microsoft OAuth</Link>\n        </li>\n        <li>\n          <Link href=\"/using-your-own-ui/sign-in/sso\">Single Sign-On</Link>\n        </li>\n      </ul>\n\n      <h2>Other</h2>\n      <ul>\n        <li>\n          <Link href=\"/using-your-own-ui/mfa\">Multi-Factor Auth</Link>\n        </li>\n        <li>\n          <Link href=\"/using-your-own-ui/verify-email\">Verify email</Link>\n        </li>\n        <li>\n          <Link href=\"/using-your-own-ui/reset-password\">Reset password</Link>\n        </li>\n        <li>\n          <Link href=\"/using-your-own-ui/users-table\">Users table</Link>\n        </li>\n        <li>\n          <Link href=\"/using-your-own-ui/update-user\">Update user</Link>\n        </li>\n      </ul>\n    </main>\n  );\n}\n"
  },
  {
    "path": "src/app/using-your-own-ui/reset-password/page.tsx",
    "content": "'use client';\n\nimport { useFormState } from 'react-dom';\nimport { sendReset, resetPassword } from './reset-password';\n\nexport default function ResetPassword({\n  searchParams,\n}: {\n  searchParams: { token?: string; email?: string };\n}) {\n  const { token, email } = searchParams;\n\n  // This example uses Next.js server actions to call functions on the server side.\n  //\n  // If your application is a single page app (SPA), you will need to:\n  // - handle the form submission in `<form onSubmit>`\n  // - make an API call to your backend (e.g using `fetch`)\n  const [sendResetState, sendResetAction] = useFormState(sendReset, { error: null });\n  const [resetPasswordState, resetPasswordAction] = useFormState(resetPassword, { error: null });\n\n  if (!token) {\n    return (\n      <main key=\"email\">\n        <h1>Reset password</h1>\n\n        <form action={sendResetAction}>\n          <div>\n            <label htmlFor=\"email\">Email</label>\n            <input\n              type=\"email\"\n              name=\"email\"\n              id=\"email\"\n              autoCapitalize=\"off\"\n              autoComplete=\"username\"\n              autoFocus\n              required\n            />\n          </div>\n\n          <button type=\"submit\">Send reset instructions</button>\n        </form>\n\n        <pre>{JSON.stringify(sendResetState, null, 2)}</pre>\n      </main>\n    );\n  }\n\n  return (\n    <main key=\"code\">\n      <h1>Reset password</h1>\n\n      <form action={resetPasswordAction}>\n        <div>\n          <label htmlFor=\"newPassword\">New Password</label>\n          <input\n            type=\"password\"\n            name=\"newPassword\"\n            id=\"newPassword\"\n            autoCapitalize=\"off\"\n            autoComplete=\"new-password\"\n            autoFocus\n            required\n          />\n        </div>\n\n        <input type=\"hidden\" name=\"token\" value={token} />\n\n        {email && (\n          // We also include the email in a hidden input so that password managers can update the password on the correct account.\n          // https://developer.1password.com/docs/web/compatible-website-design/#password-change-and-reset-forms\n          <input\n            type=\"text\"\n            name=\"email\"\n            value={email}\n            autoComplete=\"username\"\n            style={{ display: 'none' }}\n          />\n        )}\n\n        <button type=\"submit\">Continue</button>\n      </form>\n\n      <pre>{JSON.stringify(resetPasswordState, null, 2)}</pre>\n    </main>\n  );\n}\n"
  },
  {
    "path": "src/app/using-your-own-ui/reset-password/reset-password.ts",
    "content": "'use server';\n\n// These are Next.js server actions.\n//\n// If your application is a single page app (SPA) with a separate backend you will need to:\n// - create a backend endpoint to handle each request\n// - adapt the code below in each of those endpoints\n//\n// Please also note that for the sake of simplicity, we return all errors here.\n// In a real application, you should pay attention to which errors make it\n// to the client for security reasons.\n\nimport { WorkOS } from '@workos-inc/node';\n\nconst workos = new WorkOS(process.env.WORKOS_API_KEY);\n\nexport async function sendReset(prevState: any, formData: FormData) {\n  try {\n    const email = String(formData.get('email'));\n    return await workos.userManagement.sendPasswordResetEmail({\n      email,\n      passwordResetUrl: `http://localhost:3000/using-your-own-ui/reset-password?email=${email}`,\n    });\n  } catch (error) {\n    return { error: JSON.parse(JSON.stringify(error)) };\n  }\n}\n\nexport async function resetPassword(prevState: any, formData: FormData) {\n  try {\n    return await workos.userManagement.resetPassword({\n      newPassword: String(formData.get('newPassword')),\n      token: String(formData.get('token')),\n    });\n  } catch (error) {\n    return { error: JSON.parse(JSON.stringify(error)) };\n  }\n}\n"
  },
  {
    "path": "src/app/using-your-own-ui/sign-in/email-password/email-password.ts",
    "content": "'use server';\n\n// These are Next.js server actions.\n//\n// If your application is a single page app (SPA) with a separate backend you will need to:\n// - create a backend endpoint to handle each request\n// - adapt the code below in each of those endpoints\n//\n// Please also note that for the sake of simplicity, we return all errors here.\n// In a real application, you should pay attention to which errors make it\n// to the client for security reasons.\n\nimport { WorkOS } from '@workos-inc/node';\n\nconst workos = new WorkOS(process.env.WORKOS_API_KEY);\n\nexport async function signIn(prevState: any, formData: FormData) {\n  try {\n    // For the sake of simplicity, we directly return the user here.\n    // In a real application, you would probably store the user in a token (JWT)\n    // and store that token in your DB or use cookies.\n    return await workos.userManagement.authenticateWithPassword({\n      clientId: process.env.WORKOS_CLIENT_ID || '',\n      email: String(formData.get('email')),\n      password: String(formData.get('password')),\n    });\n  } catch (error) {\n    return { error: JSON.parse(JSON.stringify(error)) };\n  }\n}\n"
  },
  {
    "path": "src/app/using-your-own-ui/sign-in/email-password/page.tsx",
    "content": "'use client';\n\nimport { useFormState } from 'react-dom';\nimport { signIn } from './email-password';\n\nexport default function SignInWithEmailPassword() {\n  // This example uses Next.js server actions to call functions on the server side.\n  //\n  // If your application is a single page app (SPA), you will need to:\n  // - handle the form submission in `<form onSubmit>`\n  // - make an API call to your backend (e.g using `fetch`)\n  const [signInState, signInAction] = useFormState(signIn, { error: null });\n\n  return (\n    <main>\n      <h1>Sign-in</h1>\n      <h2>Email + Password</h2>\n\n      <form action={signInAction}>\n        <div>\n          <label htmlFor=\"email\">Email</label>\n          <input\n            type=\"email\"\n            name=\"email\"\n            id=\"email\"\n            autoCapitalize=\"off\"\n            autoComplete=\"username\"\n            autoFocus\n            required\n          />\n        </div>\n\n        <div>\n          <label htmlFor=\"password\">Password</label>\n          <input\n            type=\"password\"\n            name=\"password\"\n            id=\"password\"\n            autoCapitalize=\"off\"\n            autoComplete=\"current-password\"\n            required\n          />\n        </div>\n\n        <button type=\"submit\">Sign-in</button>\n      </form>\n\n      <pre>{JSON.stringify(signInState, null, 2)}</pre>\n    </main>\n  );\n}\n"
  },
  {
    "path": "src/app/using-your-own-ui/sign-in/github-oauth/callback/route.ts",
    "content": "import { WorkOS } from '@workos-inc/node';\nimport { redirect } from 'next/navigation';\n\n// This is a Next.js Route Handler.\n//\n// If your application is a single page app (SPA) with a separate backend you will need to:\n// - create a backend endpoint to handle the request\n// - adapt the code below in your endpoint\n//\n// Please also note that for the sake of simplicity, we directly return the user here in the query string.\n// In a real application, you would probably store the user in a token (JWT)\n// and store that token in your DB or use cookies.\n\nconst workos = new WorkOS(process.env.WORKOS_API_KEY);\n\nexport async function GET(request: Request) {\n  const code = new URL(request.url).searchParams.get('code') || '';\n\n  let response;\n\n  try {\n    response = await workos.userManagement.authenticateWithCode({\n      clientId: process.env.WORKOS_CLIENT_ID || '',\n      code,\n    });\n  } catch (error) {\n    response = error;\n  }\n\n  if (response) {\n    redirect(\n      `http://localhost:3000/using-your-own-ui/sign-in/github-oauth?response=${JSON.stringify(\n        response\n      )}`\n    );\n  }\n}\n"
  },
  {
    "path": "src/app/using-your-own-ui/sign-in/github-oauth/page.tsx",
    "content": "import { WorkOS } from '@workos-inc/node';\n\n// This example uses Next.js with React Server Components.\n// Because this page is an RSC, the code stays on the server, which allows\n// us to use the WorkOS Node SDK without exposing our API key to the client.\n//\n// If your application is a single page app (SPA), you will need to:\n// - create a form that can POST to an endpoint in your backend\n// - call the `getAuthorizationURL` method in that endpoint\n// - redirect the user to the returned URL\n\nconst workos = new WorkOS(process.env.WORKOS_API_KEY);\n\nexport default function SignInWithGitHubOAuth({\n  searchParams,\n}: {\n  searchParams: { [key: string]: string | string[] | undefined };\n}) {\n  const githubOAuthUrl = workos.userManagement.getAuthorizationUrl({\n    clientId: process.env.WORKOS_CLIENT_ID || '',\n    provider: 'GitHubOAuth',\n    redirectUri: 'http://localhost:3000/using-your-own-ui/sign-in/github-oauth/callback',\n  });\n\n  const result = JSON.parse(String(searchParams.response ?? '{ \"error\": null }'));\n\n  return (\n    <main>\n      <h1>Sign-in</h1>\n      <h2>GitHub OAuth</h2>\n      <a href={githubOAuthUrl}>Continue with GitHub</a>\n      <pre>{JSON.stringify(result, null, 2)}</pre>\n    </main>\n  );\n}\n"
  },
  {
    "path": "src/app/using-your-own-ui/sign-in/google-oauth/callback/route.ts",
    "content": "import { WorkOS } from '@workos-inc/node';\nimport { redirect } from 'next/navigation';\n\n// This is a Next.js Route Handler.\n//\n// If your application is a single page app (SPA) with a separate backend you will need to:\n// - create a backend endpoint to handle the request\n// - adapt the code below in your endpoint\n//\n// Please also note that for the sake of simplicity, we directly return the user here in the query string.\n// In a real application, you would probably store the user in a token (JWT)\n// and store that token in your DB or use cookies.\n\nconst workos = new WorkOS(process.env.WORKOS_API_KEY);\n\nexport async function GET(request: Request) {\n  const code = new URL(request.url).searchParams.get('code') || '';\n\n  let response;\n\n  try {\n    response = await workos.userManagement.authenticateWithCode({\n      clientId: process.env.WORKOS_CLIENT_ID || '',\n      code,\n    });\n  } catch (error) {\n    response = error;\n  }\n\n  if (response) {\n    redirect(\n      `http://localhost:3000/using-your-own-ui/sign-in/google-oauth?response=${JSON.stringify(\n        response\n      )}`\n    );\n  }\n}\n"
  },
  {
    "path": "src/app/using-your-own-ui/sign-in/google-oauth/page.tsx",
    "content": "import { WorkOS } from '@workos-inc/node';\n\n// This example uses Next.js with React Server Components.\n// Because this page is an RSC, the code stays on the server, which allows\n// us to use the WorkOS Node SDK without exposing our API key to the client.\n//\n// If your application is a single page app (SPA), you will need to:\n// - create a form that can POST to an endpoint in your backend\n// - call the `getAuthorizationURL` method in that endpoint\n// - redirect the user to the returned URL\n\nconst workos = new WorkOS(process.env.WORKOS_API_KEY);\n\nexport default function SignInWithGoogleOAuth({\n  searchParams,\n}: {\n  searchParams: { [key: string]: string | string[] | undefined };\n}) {\n  const googleOAuthUrl = workos.userManagement.getAuthorizationUrl({\n    clientId: process.env.WORKOS_CLIENT_ID || '',\n    provider: 'GoogleOAuth',\n    redirectUri: 'http://localhost:3000/using-your-own-ui/sign-in/google-oauth/callback',\n  });\n\n  const result = JSON.parse(String(searchParams.response ?? '{ \"error\": null }'));\n\n  return (\n    <main>\n      <h1>Sign-in</h1>\n      <h2>Google OAuth</h2>\n      <a href={googleOAuthUrl}>Continue with Google</a>\n      <pre>{JSON.stringify(result, null, 2)}</pre>\n    </main>\n  );\n}\n"
  },
  {
    "path": "src/app/using-your-own-ui/sign-in/magic-auth/magic-auth.ts",
    "content": "'use server';\n\n// These are Next.js server actions.\n//\n// If your application is a single page app (SPA) with a separate backend you will need to:\n// - create a backend endpoint to handle each request\n// - adapt the code below in each of those endpoints\n//\n// Please also note that for the sake of simplicity, we return all errors here.\n// In a real application, you should pay attention to which errors make it\n// to the client for security reasons.\n\nimport { WorkOS } from '@workos-inc/node';\n\nconst workos = new WorkOS(process.env.WORKOS_API_KEY);\n\nexport async function sendCode(prevState: any, formData: FormData) {\n  try {\n    return await workos.userManagement.sendMagicAuthCode({\n      email: String(formData.get('email')),\n    });\n  } catch (error) {\n    return { error: JSON.parse(JSON.stringify(error)) };\n  }\n}\n\nexport async function signIn(prevState: any, formData: FormData) {\n  try {\n    // For the sake of simplicity, we directly return the user here.\n    // In a real application, you would probably store the user in a token (JWT)\n    // and store that token in your DB or use cookies.\n    return await workos.userManagement.authenticateWithMagicAuth({\n      clientId: process.env.WORKOS_CLIENT_ID || '',\n      code: String(formData.get('code')),\n      email: String(formData.get('email')),\n    });\n  } catch (error) {\n    return { error: JSON.parse(JSON.stringify(error)) };\n  }\n}\n"
  },
  {
    "path": "src/app/using-your-own-ui/sign-in/magic-auth/page.tsx",
    "content": "'use client';\n\nimport * as React from 'react';\nimport { useFormState } from 'react-dom';\nimport { sendCode, signIn } from './magic-auth';\n\nexport default function SignInWithMagicAuth() {\n  // This example uses Next.js server actions to call functions on the server side.\n  //\n  // If your application is a single page app (SPA), you will need to:\n  // - handle the form submission in `<form onSubmit>`\n  // - make an API call to your backend (e.g using `fetch`)\n  const [sendCodeState, sendCodeAction] = useFormState(sendCode, { error: null });\n  const [signInState, signInAction] = useFormState(signIn, { error: null });\n  const [email, setEmail] = React.useState('');\n\n  if (sendCodeState?.error === null) {\n    return (\n      <main key=\"email\">\n        <h1>Sign-in</h1>\n        <h2>Magic Auth</h2>\n\n        <form action={sendCodeAction}>\n          <div>\n            <label htmlFor=\"email\">Email</label>\n            <input\n              type=\"email\"\n              name=\"email\"\n              id=\"email\"\n              autoCapitalize=\"off\"\n              autoComplete=\"username\"\n              autoFocus\n              required\n              onChange={(event) => setEmail(event.target.value)}\n            />\n          </div>\n\n          <button type=\"submit\">Send code</button>\n        </form>\n\n        <pre>{JSON.stringify(sendCodeState, null, 2)}</pre>\n      </main>\n    );\n  }\n\n  return (\n    <main key=\"code\">\n      <h1>Sign-in</h1>\n      <h2>Magic Auth</h2>\n\n      <form action={signInAction}>\n        <div>\n          <label htmlFor=\"code\">Enter code from the email</label>\n          <input\n            type=\"text\"\n            name=\"code\"\n            id=\"code\"\n            inputMode=\"numeric\"\n            autoComplete=\"one-time-code\"\n            pattern=\"^\\d{6}$\"\n            autoFocus\n            required\n          />\n        </div>\n\n        {/* we need the email to authenticate with the code */}\n        <input type=\"hidden\" name=\"email\" value={email} />\n\n        <button type=\"submit\">Sign-in</button>\n      </form>\n\n      <pre>{JSON.stringify(signInState, null, 2)}</pre>\n    </main>\n  );\n}\n"
  },
  {
    "path": "src/app/using-your-own-ui/sign-in/microsoft-oauth/callback/route.ts",
    "content": "import { WorkOS } from '@workos-inc/node';\nimport { redirect } from 'next/navigation';\n\n// This is a Next.js Route Handler.\n//\n// If your application is a single page app (SPA) with a separate backend you will need to:\n// - create a backend endpoint to handle the request\n// - adapt the code below in your endpoint\n//\n// Please also note that for the sake of simplicity, we directly return the user here in the query string.\n// In a real application, you would probably store the user in a token (JWT)\n// and store that token in your DB or use cookies.\n\nconst workos = new WorkOS(process.env.WORKOS_API_KEY);\n\nexport async function GET(request: Request) {\n  const code = new URL(request.url).searchParams.get('code') || '';\n\n  let response;\n\n  try {\n    response = await workos.userManagement.authenticateWithCode({\n      clientId: process.env.WORKOS_CLIENT_ID || '',\n      code,\n    });\n  } catch (error) {\n    response = error;\n  }\n\n  if (response) {\n    redirect(\n      `http://localhost:3000/using-your-own-ui/sign-in/microsoft-oauth?response=${JSON.stringify(\n        response\n      )}`\n    );\n  }\n}\n"
  },
  {
    "path": "src/app/using-your-own-ui/sign-in/microsoft-oauth/page.tsx",
    "content": "import { WorkOS } from '@workos-inc/node';\n\n// This example uses Next.js with React Server Components.\n// Because this page is an RSC, the code stays on the server, which allows\n// us to use the WorkOS Node SDK without exposing our API key to the client.\n//\n// If your application is a single page app (SPA), you will need to:\n// - create a form that can POST to an endpoint in your backend\n// - call the `getAuthorizationURL` method in that endpoint\n// - redirect the user to the returned URL\n\nconst workos = new WorkOS(process.env.WORKOS_API_KEY);\n\nexport default function SignInWithMicrosoftOAuth({\n  searchParams,\n}: {\n  searchParams: { [key: string]: string | string[] | undefined };\n}) {\n  const microsoftOAuthUrl = workos.userManagement.getAuthorizationUrl({\n    clientId: process.env.WORKOS_CLIENT_ID || '',\n    provider: 'MicrosoftOAuth',\n    redirectUri: 'http://localhost:3000/using-your-own-ui/sign-in/microsoft-oauth/callback',\n  });\n\n  const result = JSON.parse(String(searchParams.response ?? '{ \"error\": null }'));\n\n  return (\n    <main>\n      <h1>Sign-in</h1>\n      <h2>Microsoft OAuth</h2>\n      <a href={microsoftOAuthUrl}>Continue with Microsoft</a>\n      <pre>{JSON.stringify(result, null, 2)}</pre>\n    </main>\n  );\n}\n"
  },
  {
    "path": "src/app/using-your-own-ui/sign-in/sso/callback/route.ts",
    "content": "import { WorkOS } from '@workos-inc/node';\nimport { redirect } from 'next/navigation';\n\n// This is a Next.js Route Handler.\n//\n// If your application is a single page app (SPA) with a separate backend you will need to:\n// - create a backend endpoint to handle the request\n// - adapt the code below in your endpoint\n//\n// Please also note that for the sake of simplicity, we directly return the user here in the query string.\n// In a real application, you would probably store the user in a token (JWT)\n// and store that token in your DB or use cookies.\n\nconst workos = new WorkOS(process.env.WORKOS_API_KEY);\n\nexport async function GET(request: Request) {\n  const code = new URL(request.url).searchParams.get('code') || '';\n\n  let response;\n\n  try {\n    response = await workos.userManagement.authenticateWithCode({\n      clientId: process.env.WORKOS_CLIENT_ID || '',\n      code,\n    });\n  } catch (error) {\n    response = error;\n  }\n\n  if (response) {\n    redirect(\n      `http://localhost:3000/using-your-own-ui/sign-in/sso?response=${JSON.stringify(response)}`\n    );\n  }\n}\n"
  },
  {
    "path": "src/app/using-your-own-ui/sign-in/sso/page.tsx",
    "content": "import { WorkOS } from '@workos-inc/node';\n\n// This example uses Next.js with React Server Components.\n// Because this page is an RSC, the code stays on the server, which allows\n// us to use the WorkOS Node SDK without exposing our API key to the client.\n//\n// If your application is a single page app (SPA), you will need to:\n// - create a form that can POST to an endpoint in your backend\n// - call the `getAuthorizationURL` method in that endpoint\n// - redirect the user to the returned URL\n\nconst workos = new WorkOS(process.env.WORKOS_API_KEY);\n\nexport default function SignInWithSSO({\n  searchParams,\n}: {\n  searchParams: { [key: string]: string | string[] | undefined };\n}) {\n  const ssoUrl = workos.userManagement.getAuthorizationUrl({\n    clientId: process.env.WORKOS_CLIENT_ID || '',\n    organizationId: process.env.SSO_ENABLED_ORGANIZATION_ID || '',\n    redirectUri: 'http://localhost:3000/using-your-own-ui/sign-in/sso/callback',\n  });\n\n  const result = JSON.parse(String(searchParams.response ?? '{ \"error\": null }'));\n\n  return (\n    <main>\n      <h1>Sign-in</h1>\n      <h2>Single Sign-On</h2>\n      <a href={ssoUrl}>Continue with SSO</a>\n      <pre>{JSON.stringify(result, null, 2)}</pre>\n    </main>\n  );\n}\n"
  },
  {
    "path": "src/app/using-your-own-ui/sign-up/email-password/email-password.ts",
    "content": "'use server';\n\n// These are Next.js server actions.\n//\n// If your application is a single page app (SPA) with a separate backend you will need to:\n// - create a backend endpoint to handle each request\n// - adapt the code below in each of those endpoints\n//\n// Please also note that for the sake of simplicity, we return all errors here.\n// In a real application, you should pay attention to which errors make it\n// to the client for security reasons.\n\nimport { WorkOS } from '@workos-inc/node';\n\nconst workos = new WorkOS(process.env.WORKOS_API_KEY);\n\nexport async function signUp(prevState: any, formData: FormData) {\n  try {\n    // For the sake of simplicity, we directly return the user here.\n    // In a real application, you would probably redirect the user to sign-in.\n    return await workos.userManagement.createUser({\n      email: String(formData.get('email')),\n      password: String(formData.get('password')),\n      firstName: String(formData.get('firstName')),\n      lastName: String(formData.get('lastName')),\n    });\n  } catch (error) {\n    return { error: JSON.parse(JSON.stringify(error)) };\n  }\n}\n"
  },
  {
    "path": "src/app/using-your-own-ui/sign-up/email-password/page.tsx",
    "content": "'use client';\n\nimport { useFormState } from 'react-dom';\nimport { signUp } from './email-password';\n\nexport default function SignUpWithEmailPassword() {\n  // This example uses Next.js server actions to call functions on the server side.\n  //\n  // If your application is a single page app (SPA), you will need to:\n  // - handle the form submission in `<form onSubmit>`\n  // - make an API call to your backend (e.g using `fetch`)\n  const [signUpState, signUpAction] = useFormState(signUp, { error: null });\n\n  return (\n    <main>\n      <h1>Sign-up</h1>\n      <h2>Email + Password</h2>\n\n      <form action={signUpAction}>\n        <div>\n          <label htmlFor=\"email\">Email</label>\n          <input\n            type=\"email\"\n            name=\"email\"\n            id=\"email\"\n            autoCapitalize=\"off\"\n            autoComplete=\"username\"\n            autoFocus\n            required\n          />\n        </div>\n\n        <div>\n          <label htmlFor=\"password\">Password</label>\n          <input\n            type=\"password\"\n            name=\"password\"\n            id=\"password\"\n            autoCapitalize=\"off\"\n            autoComplete=\"new-password\"\n            required\n          />\n        </div>\n\n        <div>\n          <label htmlFor=\"firstName\">First Name</label>\n          <input type=\"text\" name=\"firstName\" id=\"firstName\" autoComplete=\"given-name\" />\n        </div>\n\n        <div>\n          <label htmlFor=\"lastName\">Last Name</label>\n          <input type=\"text\" name=\"lastName\" id=\"lastName\" autoComplete=\"family-name\" />\n        </div>\n\n        <button type=\"submit\">Sign-up</button>\n      </form>\n\n      <pre>{JSON.stringify(signUpState, null, 2)}</pre>\n    </main>\n  );\n}\n"
  },
  {
    "path": "src/app/using-your-own-ui/sign-up/magic-auth/magic-auth.ts",
    "content": "'use server';\n\n// These are Next.js server actions.\n//\n// If your application is a single page app (SPA) with a separate backend you will need to:\n// - create a backend endpoint to handle each request\n// - adapt the code below in each of those endpoints\n//\n// Please also note that for the sake of simplicity, we return all errors here.\n// In a real application, you should pay attention to which errors make it\n// to the client for security reasons.\n\nimport { WorkOS } from '@workos-inc/node';\n\nconst workos = new WorkOS(process.env.WORKOS_API_KEY);\n\nexport async function signUp(prevState: any, formData: FormData) {\n  try {\n    // For the sake of simplicity, we directly return the user here.\n    // In a real application, you would probably send a magic code email\n    // and redirect the user to a page where they can enter the code.\n    // See the `sign-in/magic-auth` example for more details.\n    return await workos.userManagement.createUser({\n      email: String(formData.get('email')),\n      password: undefined,\n      firstName: String(formData.get('firstName')),\n      lastName: String(formData.get('lastName')),\n    });\n  } catch (error) {\n    return { error: JSON.parse(JSON.stringify(error)) };\n  }\n}\n"
  },
  {
    "path": "src/app/using-your-own-ui/sign-up/magic-auth/page.tsx",
    "content": "'use client';\n\nimport { useFormState } from 'react-dom';\nimport { signUp } from './magic-auth';\n\nexport default function SignUpWithMagicAuth() {\n  // This example uses Next.js server actions to call functions on the server side.\n  //\n  // If your application is a single page app (SPA), you will need to:\n  // - handle the form submission in `<form onSubmit>`\n  // - make an API call to your backend (e.g using `fetch`)\n  const [signUpState, signUpAction] = useFormState(signUp, { error: null });\n\n  return (\n    <main>\n      <h1>Sign-up</h1>\n      <h2>Magic Auth</h2>\n\n      <form action={signUpAction}>\n        <div>\n          <label htmlFor=\"email\">Email</label>\n          <input\n            type=\"email\"\n            name=\"email\"\n            id=\"email\"\n            autoCapitalize=\"off\"\n            autoComplete=\"username\"\n            autoFocus\n            required\n          />\n        </div>\n\n        <div>\n          <label htmlFor=\"firstName\">First Name</label>\n          <input type=\"text\" name=\"firstName\" id=\"firstName\" autoComplete=\"given-name\" />\n        </div>\n\n        <div>\n          <label htmlFor=\"lastName\">Last Name</label>\n          <input type=\"text\" name=\"lastName\" id=\"lastName\" autoComplete=\"family-name\" />\n        </div>\n\n        <button type=\"submit\">Sign-up</button>\n      </form>\n\n      <pre>{JSON.stringify(signUpState, null, 2)}</pre>\n    </main>\n  );\n}\n"
  },
  {
    "path": "src/app/using-your-own-ui/update-user/page.tsx",
    "content": "'use client';\n\nimport { useFormState } from 'react-dom';\nimport { getUser, updateUser } from './update-user';\n\nexport default function UpdateUser() {\n  // This example uses Next.js server actions to call functions on the server side.\n  //\n  // If your application is a single page app (SPA), you will need to:\n  // - handle the form submission in `<form onSubmit>`\n  // - make an API call to your backend (e.g using `fetch`)\n  const [getUserState, getUserAction] = useFormState(getUser, { error: null });\n  const [updateUserState, updateUserAction] = useFormState(updateUser, { error: null });\n\n  if (!('user' in getUserState)) {\n    return (\n      <main key=\"email\">\n        <h1>Update user</h1>\n\n        <form action={getUserAction}>\n          <div>\n            <label htmlFor=\"email\">Email</label>\n            <input\n              type=\"email\"\n              name=\"email\"\n              id=\"email\"\n              autoCapitalize=\"off\"\n              autoComplete=\"username\"\n              autoFocus\n              required\n            />\n          </div>\n\n          <button type=\"submit\">Continue</button>\n        </form>\n\n        <pre>{JSON.stringify(getUserState, null, 2)}</pre>\n      </main>\n    );\n  }\n\n  return (\n    <main key=\"code\">\n      <h1>Update user</h1>\n\n      <form action={updateUserAction}>\n        <div>\n          <label htmlFor=\"email\">Email</label>\n          <input type=\"text\" name=\"email\" id=\"email\" readOnly value={getUserState.user.email} />\n        </div>\n\n        <div>\n          <label htmlFor=\"firstName\">First Name</label>\n          <input\n            type=\"firstName\"\n            name=\"firstName\"\n            id=\"firstName\"\n            autoComplete=\"given-name\"\n            defaultValue={getUserState.user.firstName ?? ''}\n            autoFocus\n          />\n        </div>\n\n        <div>\n          <label htmlFor=\"lastName\">Last Name</label>\n          <input\n            type=\"lastName\"\n            name=\"lastName\"\n            id=\"lastName\"\n            autoComplete=\"family-name\"\n            defaultValue={getUserState.user.lastName ?? ''}\n          />\n        </div>\n\n        <input type=\"hidden\" name=\"userId\" value={getUserState.user.id} />\n\n        <button type=\"submit\">Update user details</button>\n      </form>\n\n      <pre>{JSON.stringify(updateUserState, null, 2)}</pre>\n    </main>\n  );\n}\n"
  },
  {
    "path": "src/app/using-your-own-ui/update-user/update-user.ts",
    "content": "'use server';\n\n// These are Next.js server actions.\n//\n// If your application is a single page app (SPA) with a separate backend you will need to:\n// - create a backend endpoint to handle each request\n// - adapt the code below in each of those endpoints\n//\n// Please also note that for the sake of simplicity, we return all errors here.\n// In a real application, you should pay attention to which errors make it\n// to the client for security reasons.\n\nimport { WorkOS } from '@workos-inc/node';\nimport type { User } from '@workos-inc/node';\nimport { revalidatePath } from 'next/cache';\n\nconst workos = new WorkOS(process.env.WORKOS_API_KEY);\n\nexport async function getUser(prevState: any, formData: FormData): Promise<Response> {\n  try {\n    const users = await workos.userManagement.listUsers({ email: String(formData.get('email')) });\n    const user = users.data[0];\n    return { user };\n  } catch (error) {\n    return { error: JSON.parse(JSON.stringify(error)) };\n  }\n}\n\nexport async function updateUser(prevState: any, formData: FormData): Promise<Response> {\n  try {\n    const user = await workos.userManagement.updateUser({\n      userId: String(formData.get('userId')),\n      firstName: String(formData.get('firstName')),\n      lastName: String(formData.get('lastName')),\n    });\n    revalidatePath('/users-table');\n    return { user };\n  } catch (error) {\n    return { error: JSON.parse(JSON.stringify(error)) };\n  }\n}\n\ntype Response = { user: User } | { error: any };\n"
  },
  {
    "path": "src/app/using-your-own-ui/users-table/loading.tsx",
    "content": "export default function Loading() {\n  return (\n    <main>\n      <h1>Users</h1>\n\n      <table>\n        <thead>\n          <tr>\n            <th style={{ width: '40%' }}>Email</th>\n            <th>Name</th>\n            <th style={{ width: '10%', textAlign: 'center' }}>Verified</th>\n            <th style={{ width: '10%', textAlign: 'right' }} />\n          </tr>\n        </thead>\n        <tbody>\n          {Array.from({ length: 3 }, (_, i) => (\n            <tr key={i}>\n              <td>…</td>\n              <td>…</td>\n              <td style={{ textAlign: 'center' }}>…</td>\n              <td>\n                <button style={{ visibility: 'hidden' }}>Delete</button>\n              </td>\n            </tr>\n          ))}\n        </tbody>\n      </table>\n      <nav>&nbsp;</nav>\n    </main>\n  );\n}\n"
  },
  {
    "path": "src/app/using-your-own-ui/users-table/page.tsx",
    "content": "import { WorkOS } from '@workos-inc/node';\nimport type { User } from '@workos-inc/node';\nimport Link from 'next/link';\nimport { deleteUser } from './users-table';\n\n// This example uses Next.js with React Server Components.\n// Because this page is an RSC, the code stays on the server, which allows\n// us to use the WorkOS Node SDK without exposing our API key to the client.\n//\n// If your application is a single page app (SPA), you will need to:\n// - create a backend endpoint to return the list of users\n// - adapt the code below in your endpoint\n// - make an API call to your backend (e.g using `fetch`)\n\nconst workos = new WorkOS(process.env.WORKOS_API_KEY);\n\nexport default async function UsersTable({\n  searchParams,\n}: {\n  searchParams: { before?: string; after?: string };\n}) {\n  const users = await workos.userManagement.listUsers({ limit: 5, ...searchParams });\n  const { before, after } = users.listMetadata;\n\n  return (\n    <main>\n      <h1>Users</h1>\n\n      <table>\n        <thead>\n          <tr>\n            <th style={{ width: '40%' }}>Email</th>\n            <th>Name</th>\n            <th style={{ width: '10%', textAlign: 'center' }}>Verified</th>\n            <th style={{ width: '10%', textAlign: 'right' }} />\n          </tr>\n        </thead>\n        <tbody>\n          {users.data.map((user) => (\n            <tr key={user.id}>\n              <td title={user.id}>{user.email}</td>\n              <td>{formatName(user)}</td>\n              <td style={{ textAlign: 'center' }}>{user.emailVerified ? 'Yes' : 'No'}</td>\n              <td style={{ textAlign: 'right' }}>\n                <form action={deleteUser}>\n                  <input type=\"hidden\" name=\"userId\" value={user.id} />\n                  <button type=\"submit\">Delete</button>\n                </form>\n              </td>\n            </tr>\n          ))}\n        </tbody>\n      </table>\n\n      <nav>\n        {before ? <Link href={`?before=${before}`}>Previous</Link> : 'Previous'}\n        {after ? <Link href={`?after=${after}`}>Next</Link> : 'Next'}\n      </nav>\n    </main>\n  );\n}\n\nfunction formatName(user: User) {\n  if (user.firstName && user.lastName) {\n    return `${user.firstName} ${user.lastName}`;\n  } else {\n    return user.lastName ?? user.firstName ?? '';\n  }\n}\n"
  },
  {
    "path": "src/app/using-your-own-ui/users-table/users-table.ts",
    "content": "'use server';\n\n// These are Next.js server actions.\n//\n// If your application is a single page app (SPA) with a separate backend you will need to:\n// - create a backend endpoint to handle each request\n// - adapt the code below in each of those endpoints\n//\n// Please also note that for the sake of simplicity, we return all errors here.\n// In a real application, you should pay attention to which errors make it\n// to the client for security reasons.\n\nimport { WorkOS } from '@workos-inc/node';\nimport { revalidatePath } from 'next/cache';\n\nconst workos = new WorkOS(process.env.WORKOS_API_KEY);\n\nexport async function deleteUser(formData: FormData) {\n  try {\n    await workos.userManagement.deleteUser(String(formData.get('userId')));\n    revalidatePath('/users-table');\n  } catch (error) {\n    console.log(error);\n  }\n}\n"
  },
  {
    "path": "src/app/using-your-own-ui/verify-email/page.tsx",
    "content": "'use client';\n\nimport { useFormState } from 'react-dom';\nimport { sendCode, verifyEmail } from './verify-email';\n\nexport default function VerifyEmail() {\n  // This example uses Next.js server actions to call functions on the server side.\n  //\n  // If your application is a single page app (SPA), you will need to:\n  // - handle the form submission in `<form onSubmit>`\n  // - make an API call to your backend (e.g using `fetch`)\n  const [sendCodeState, sendCodeAction] = useFormState(sendCode, { error: null });\n  const [verifyEmailState, verifyEmailAction] = useFormState(verifyEmail, { error: null });\n\n  if (!('user' in sendCodeState)) {\n    return (\n      <main key=\"email\">\n        <h1>Verify email</h1>\n\n        <form action={sendCodeAction}>\n          <div>\n            <label htmlFor=\"email\">Email</label>\n            <input\n              type=\"email\"\n              name=\"email\"\n              id=\"email\"\n              autoCapitalize=\"off\"\n              autoComplete=\"username\"\n              autoFocus\n              required\n            />\n          </div>\n\n          <button type=\"submit\">Send code</button>\n        </form>\n\n        <pre>{JSON.stringify(sendCodeState, null, 2)}</pre>\n      </main>\n    );\n  }\n\n  return (\n    <main key=\"code\">\n      <h1>Verify email</h1>\n\n      <form action={verifyEmailAction}>\n        <div>\n          <label htmlFor=\"code\">Enter code from the email</label>\n          <input\n            type=\"text\"\n            name=\"code\"\n            id=\"code\"\n            inputMode=\"numeric\"\n            autoComplete=\"one-time-code\"\n            pattern=\"^\\d{6}$\"\n            autoFocus\n            required\n          />\n        </div>\n\n        <input type=\"hidden\" name=\"userId\" value={sendCodeState.user.id} />\n\n        <button type=\"submit\">Continue</button>\n      </form>\n\n      <pre>{JSON.stringify(verifyEmailState, null, 2)}</pre>\n    </main>\n  );\n}\n"
  },
  {
    "path": "src/app/using-your-own-ui/verify-email/verify-email.ts",
    "content": "'use server';\n\n// These are Next.js server actions.\n//\n// If your application is a single page app (SPA) with a separate backend you will need to:\n// - create a backend endpoint to handle each request\n// - adapt the code below in each of those endpoints\n//\n// Please also note that for the sake of simplicity, we return all errors here.\n// In a real application, you should pay attention to which errors make it\n// to the client for security reasons.\n\nimport { WorkOS } from '@workos-inc/node';\nimport { revalidatePath } from 'next/cache';\n\nconst workos = new WorkOS(process.env.WORKOS_API_KEY);\n\nexport async function sendCode(prevState: any, formData: FormData) {\n  try {\n    const users = await workos.userManagement.listUsers({ email: String(formData.get('email')) });\n    const user = users.data[0];\n    return await workos.userManagement.sendVerificationEmail({ userId: user.id });\n  } catch (error) {\n    return { error: JSON.parse(JSON.stringify(error)) };\n  }\n}\n\nexport async function verifyEmail(prevState: any, formData: FormData) {\n  try {\n    const response = await workos.userManagement.verifyEmail({\n      userId: String(formData.get('userId')),\n      code: String(formData.get('code')),\n    });\n    revalidatePath('/users-table');\n    return response;\n  } catch (error) {\n    return { error: JSON.parse(JSON.stringify(error)) };\n  }\n}\n"
  },
  {
    "path": "src/middleware.ts",
    "content": "// This file is only used in conjunction with the authkit-nextjs library\nimport { authkitMiddleware } from '@workos-inc/authkit-nextjs';\n\nexport default authkitMiddleware({ debug: true });\n\n// Match against pages that require auth, e.g.:\nexport const config = { matcher: ['/using-hosted-authkit/with-nextjs'] };\n"
  },
  {
    "path": "tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"target\": \"es5\",\n    \"lib\": [\"dom\", \"dom.iterable\", \"esnext\"],\n    \"allowJs\": true,\n    \"skipLibCheck\": true,\n    \"strict\": true,\n    \"noEmit\": true,\n    \"esModuleInterop\": true,\n    \"module\": \"esnext\",\n    \"moduleResolution\": \"bundler\",\n    \"resolveJsonModule\": true,\n    \"isolatedModules\": true,\n    \"jsx\": \"preserve\",\n    \"incremental\": true,\n    \"plugins\": [\n      {\n        \"name\": \"next\"\n      }\n    ],\n    \"paths\": {\n      \"@/*\": [\"./src/*\"]\n    }\n  },\n  \"include\": [\"next-env.d.ts\", \"**/*.ts\", \"**/*.tsx\", \".next/types/**/*.ts\"],\n  \"exclude\": [\"node_modules\"]\n}\n"
  }
]