Repository: workos/authkit
Branch: main
Commit: abb80ebad1b6
Files: 55
Total size: 73.6 KB
Directory structure:
gitextract_xtqy99mp/
├── .eslintrc.json
├── .github/
│ └── workflows/
│ ├── coana-analysis.yml
│ └── coana-guardrail.yml
├── .gitignore
├── .prettierrc
├── CODE_OF_CONDUCT.md
├── LICENSE
├── README.md
├── context7.json
├── next.config.js
├── package.json
├── src/
│ ├── app/
│ │ ├── back-link.tsx
│ │ ├── globals.css
│ │ ├── layout.tsx
│ │ ├── page.tsx
│ │ ├── using-hosted-authkit/
│ │ │ ├── README.md
│ │ │ ├── basic/
│ │ │ │ ├── callback/
│ │ │ │ │ └── route.ts
│ │ │ │ └── page.tsx
│ │ │ ├── page.tsx
│ │ │ ├── with-nextjs/
│ │ │ │ ├── callback/
│ │ │ │ │ └── route.ts
│ │ │ │ └── page.tsx
│ │ │ └── with-session/
│ │ │ ├── auth.ts
│ │ │ ├── callback/
│ │ │ │ └── route.ts
│ │ │ └── page.tsx
│ │ └── using-your-own-ui/
│ │ ├── README.md
│ │ ├── mfa/
│ │ │ ├── mfa.ts
│ │ │ └── page.tsx
│ │ ├── page.tsx
│ │ ├── reset-password/
│ │ │ ├── page.tsx
│ │ │ └── reset-password.ts
│ │ ├── sign-in/
│ │ │ ├── email-password/
│ │ │ │ ├── email-password.ts
│ │ │ │ └── page.tsx
│ │ │ ├── github-oauth/
│ │ │ │ ├── callback/
│ │ │ │ │ └── route.ts
│ │ │ │ └── page.tsx
│ │ │ ├── google-oauth/
│ │ │ │ ├── callback/
│ │ │ │ │ └── route.ts
│ │ │ │ └── page.tsx
│ │ │ ├── magic-auth/
│ │ │ │ ├── magic-auth.ts
│ │ │ │ └── page.tsx
│ │ │ ├── microsoft-oauth/
│ │ │ │ ├── callback/
│ │ │ │ │ └── route.ts
│ │ │ │ └── page.tsx
│ │ │ └── sso/
│ │ │ ├── callback/
│ │ │ │ └── route.ts
│ │ │ └── page.tsx
│ │ ├── sign-up/
│ │ │ ├── email-password/
│ │ │ │ ├── email-password.ts
│ │ │ │ └── page.tsx
│ │ │ └── magic-auth/
│ │ │ ├── magic-auth.ts
│ │ │ └── page.tsx
│ │ ├── update-user/
│ │ │ ├── page.tsx
│ │ │ └── update-user.ts
│ │ ├── users-table/
│ │ │ ├── loading.tsx
│ │ │ ├── page.tsx
│ │ │ └── users-table.ts
│ │ └── verify-email/
│ │ ├── page.tsx
│ │ └── verify-email.ts
│ └── middleware.ts
└── tsconfig.json
================================================
FILE CONTENTS
================================================
================================================
FILE: .eslintrc.json
================================================
{
"extends": "next/core-web-vitals"
}
================================================
FILE: .github/workflows/coana-analysis.yml
================================================
name: Coana Vulnerability Analysis
on:
schedule:
- cron: "0 3 * * *" # every day at 3 AM
workflow_dispatch:
inputs:
tags:
description: "Manually run vulnerability analysis"
# Required by the return-dispatch action
distinct_id:
jobs:
coana-vulnerability-analysis:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Run Coana CLI
id: coana-cli
uses: docker://coana/coana:latest@sha256:74144ed0fc9d7da87dcd45ccd12458cc7c25ad23e47eebd7ceb4860ed396d63e
with:
args: |
coana run . \
--api-key ${{ secrets.COANA_API_KEY }} \
--repo-url https://github.com/${{github.repository}}
================================================
FILE: .github/workflows/coana-guardrail.yml
================================================
name: Coana Guardrail
on: pull_request
jobs:
guardrail:
runs-on: ubuntu-latest
steps:
- name: Checkout the ${{github.base_ref}} branch
uses: actions/checkout@v4
with:
ref: ${{github.base_ref}} # checkout the base branch (usually master/main).
- name: Fetch the PR branch
run: |
git fetch ${{ github.event.pull_request.head.repo.clone_url }} ${{ github.head_ref }}:${{ github.head_ref }} --depth=1
- name: Get list of changed files relative to the main/master branch
id: changed-files
run: |
echo "all_changed_files=$(git diff --name-only ${{ github.base_ref }} ${{ github.head_ref }} | tr '\n' ' ')" >> $GITHUB_OUTPUT
- name: Use Node.js 20.x
uses: actions/setup-node@v4
with:
node-version: 20.x
- name: Run Coana on the ${{github.base_ref}} branch
run: |
npx @coana-tech/cli run . \
--guardrail-mode \
--api-key ${{ secrets.COANA_API_KEY || 'api-key-unavailable' }} \
-o /tmp/main-branch \
--changed-files ${{ steps.changed-files.outputs.all_changed_files }} \
--lightweight-reachability \
# Reset file permissions.
# This is necessary because the Coana CLI may add
# new files with root ownership since it's using docker.
# These files will not be deleted by the clean step in checkout
# if the permissions are not reset.
- name: Reset file permissions
run: sudo chown -R $USER:$USER .
- name: Checkout the current branch
uses: actions/checkout@v4
with:
clean: true
- name: Run Coana on the current branch
run: |
npx @coana-tech/cli run . \
--guardrail-mode \
--api-key ${{ secrets.COANA_API_KEY || 'api-key-unavailable' }} \
-o /tmp/current-branch \
--changed-files ${{ steps.changed-files.outputs.all_changed_files }} \
--lightweight-reachability \
- name: Run Report Comparison
run: |
npx @coana-tech/cli compare-reports \
--api-key ${{ secrets.COANA_API_KEY || 'api-key-unavailable' }} \
/tmp/main-branch/coana-report.json \
/tmp/current-branch/coana-report.json
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
================================================
FILE: .gitignore
================================================
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/node_modules
/.pnp
.pnp.js
.yarn/install-state.gz
# testing
/coverage
# next.js
/.next/
/out/
# production
/build
# misc
.DS_Store
*.pem
# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# local env files
.env*.local
# vercel
.vercel
# typescript
*.tsbuildinfo
next-env.d.ts
================================================
FILE: .prettierrc
================================================
{
"printWidth": 100,
"singleQuote": true
}
================================================
FILE: CODE_OF_CONDUCT.md
================================================
# Contributor Covenant Code of Conduct
## Our Pledge
We as members, contributors, and leaders pledge to make participation in our
community a harassment-free experience for everyone, regardless of age, body
size, visible or invisible disability, ethnicity, sex characteristics, gender
identity and expression, level of experience, education, socio-economic status,
nationality, personal appearance, race, religion, or sexual identity
and orientation.
We pledge to act and interact in ways that contribute to an open, welcoming,
diverse, inclusive, and healthy community.
## Our Standards
Examples of behavior that contributes to a positive environment for our
community include:
* Demonstrating empathy and kindness toward other people
* Being respectful of differing opinions, viewpoints, and experiences
* Giving and gracefully accepting constructive feedback
* Accepting responsibility and apologizing to those affected by our mistakes,
and learning from the experience
* Focusing on what is best not just for us as individuals, but for the
overall community
Examples of unacceptable behavior include:
* The use of sexualized language or imagery, and sexual attention or
advances of any kind
* Trolling, insulting or derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or email
address, without their explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Enforcement Responsibilities
Community leaders are responsible for clarifying and enforcing our standards of
acceptable behavior and will take appropriate and fair corrective action in
response to any behavior that they deem inappropriate, threatening, offensive,
or harmful.
Community leaders have the right and responsibility to remove, edit, or reject
comments, commits, code, wiki edits, issues, and other contributions that are
not aligned to this Code of Conduct, and will communicate reasons for moderation
decisions when appropriate.
## Scope
This Code of Conduct applies within all community spaces, and also applies when
an individual is officially representing the community in public spaces.
Examples of representing our community include using an official e-mail address,
posting via an official social media account, or acting as an appointed
representative at an online or offline event.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported to the community leaders responsible for enforcement at
support@workos.com.
All complaints will be reviewed and investigated promptly and fairly.
All community leaders are obligated to respect the privacy and security of the
reporter of any incident.
## Enforcement Guidelines
Community leaders will follow these Community Impact Guidelines in determining
the consequences for any action they deem in violation of this Code of Conduct:
### 1. Correction
**Community Impact**: Use of inappropriate language or other behavior deemed
unprofessional or unwelcome in the community.
**Consequence**: A private, written warning from community leaders, providing
clarity around the nature of the violation and an explanation of why the
behavior was inappropriate. A public apology may be requested.
### 2. Warning
**Community Impact**: A violation through a single incident or series
of actions.
**Consequence**: A warning with consequences for continued behavior. No
interaction with the people involved, including unsolicited interaction with
those enforcing the Code of Conduct, for a specified period of time. This
includes avoiding interactions in community spaces as well as external channels
like social media. Violating these terms may lead to a temporary or
permanent ban.
### 3. Temporary Ban
**Community Impact**: A serious violation of community standards, including
sustained inappropriate behavior.
**Consequence**: A temporary ban from any sort of interaction or public
communication with the community for a specified period of time. No public or
private interaction with the people involved, including unsolicited interaction
with those enforcing the Code of Conduct, is allowed during this period.
Violating these terms may lead to a permanent ban.
### 4. Permanent Ban
**Community Impact**: Demonstrating a pattern of violation of community
standards, including sustained inappropriate behavior, harassment of an
individual, or aggression toward or disparagement of classes of individuals.
**Consequence**: A permanent ban from any sort of public interaction within
the community.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
version 2.0, available at
https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
Community Impact Guidelines were inspired by [Mozilla's code of conduct
enforcement ladder](https://github.com/mozilla/diversity).
[homepage]: https://www.contributor-covenant.org
For answers to common questions about this code of conduct, see the FAQ at
https://www.contributor-covenant.org/faq. Translations are available at
https://www.contributor-covenant.org/translations.
================================================
FILE: LICENSE
================================================
MIT License
Copyright (c) 2023 WorkOS
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: README.md
================================================
AuthKit
How to use AuthKit's hosted UI or build your own frontend with the headless User Management APIs
## Setup
First, ensure you have set up the [environment variables](/#environment-variables) and [redirects](/#redirects).
For 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**.
For 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.
In 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.
## Examples
- [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).
- [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.
- [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).
### Next.js
For the `authkit-nextjs` example, you'll need to add the following to your environment variables:
```bash
# Needed for authkit-nextjs library example, defined in WorkOS dashboard
WORKOS_REDIRECT_URI=
# Needed for authkit-nextjs library example. Must be at least 32 characters long
WORKOS_COOKIE_PASSWORD=
```
To 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:
```bash
openssl rand -base64 24
```
### Sessions
For 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.
```bash
openssl rand -base64 32
```
And update the `.env.local` file:
```bash
# ...
JWT_SECRET_KEY=""
```
================================================
FILE: src/app/using-hosted-authkit/basic/callback/route.ts
================================================
import { WorkOS } from '@workos-inc/node';
import { redirect } from 'next/navigation';
// This is a Next.js Route Handler.
//
// If your application is a single page app (SPA) with a separate backend you will need to:
// - create a backend endpoint to handle the request
// - adapt the code below in your endpoint
//
// Please also note that for the sake of simplicity, we directly return the user here in the query string.
// In a real application, you would probably store the user in a token (JWT)
// and store that token in your DB or use cookies (See `with-session` example for more details).
const workos = new WorkOS(process.env.WORKOS_API_KEY);
export async function GET(request: Request) {
const code = new URL(request.url).searchParams.get('code') || '';
let response;
try {
response = await workos.userManagement.authenticateWithCode({
clientId: process.env.WORKOS_CLIENT_ID || '',
code,
});
} catch (error) {
response = error;
}
if (response) {
redirect(
`http://localhost:3000/using-hosted-authkit/basic?response=${JSON.stringify(response)}`
);
}
}
================================================
FILE: src/app/using-hosted-authkit/basic/page.tsx
================================================
import { WorkOS } from '@workos-inc/node';
// This example uses Next.js with React Server Components.
// Because this page is an RSC, the code stays on the server, which allows
// us to use the WorkOS Node SDK without exposing our API key to the client.
//
// If your application is a single page app (SPA), you will need to:
// - create a form that can POST to an endpoint in your backend
// - call the `getAuthorizationURL` method in that endpoint
// - redirect the user to the returned URL
const workos = new WorkOS(process.env.WORKOS_API_KEY);
export default function Basic({
searchParams,
}: {
searchParams: { [key: string]: string | string[] | undefined };
}) {
const authKitUrl = workos.userManagement.getAuthorizationUrl({
clientId: process.env.WORKOS_CLIENT_ID || '',
provider: 'authkit',
redirectUri: 'http://localhost:3000/using-hosted-authkit/basic/callback',
});
const result = JSON.parse(String(searchParams.response ?? '{ "error": null }'));
return (
);
}
================================================
FILE: src/app/using-hosted-authkit/page.tsx
================================================
import Link from 'next/link';
export default function UsingHostedAuthKit() {
return (
Using hosted AuthKit
Basic example
With Next.js library
With session
);
}
================================================
FILE: src/app/using-hosted-authkit/with-nextjs/callback/route.ts
================================================
import { handleAuth } from '@workos-inc/authkit-nextjs';
export const GET = handleAuth({ returnPathname: '/using-hosted-authkit/with-nextjs/' });
================================================
FILE: src/app/using-hosted-authkit/with-nextjs/page.tsx
================================================
import { getSignInUrl, getUser, signOut } from '@workos-inc/authkit-nextjs';
export default async function WithNextjs() {
// Retrieves the user from the session or returns `null` if no user is signed in
const { user } = await getUser();
// Get the URL to redirect the user to AuthKit to sign in
const signInUrl = await getSignInUrl();
return (
Using hosted AuthKit
With Next.js library
{user ? (
<>
Welcome back {user?.firstName && `, ${user?.firstName}`}
);
}
================================================
FILE: src/app/using-hosted-authkit/with-session/auth.ts
================================================
import { cookies } from 'next/headers';
import { redirect } from 'next/navigation';
import { jwtVerify } from 'jose';
import type { User } from '@workos-inc/node';
export function getJwtSecretKey() {
const secret = process.env.JWT_SECRET_KEY;
if (!secret) {
throw new Error('JWT_SECRET_KEY is not set');
}
return new Uint8Array(Buffer.from(secret, 'base64'));
}
export async function verifyJwtToken(token: string) {
try {
const { payload } = await jwtVerify(token, getJwtSecretKey());
return payload;
} catch (error) {
return null;
}
}
// Verify the JWT and return the user
export async function getUser(): Promise<{
isAuthenticated: boolean;
user?: User | null;
}> {
const token = cookies().get('token')?.value;
if (token) {
const verifiedToken = await verifyJwtToken(token);
if (verifiedToken) {
return {
isAuthenticated: true,
user: verifiedToken.user as User | null,
};
}
}
return { isAuthenticated: false };
}
// Clear the session and redirect to the home page
export async function signOut() {
cookies().delete('token');
redirect('/using-hosted-authkit/with-session');
}
================================================
FILE: src/app/using-hosted-authkit/with-session/callback/route.ts
================================================
import { WorkOS } from '@workos-inc/node';
import { NextResponse } from 'next/server';
import { SignJWT } from 'jose';
import { getJwtSecretKey } from '../auth';
// This is a Next.js Route Handler.
//
// If your application is a single page app (SPA) with a separate backend you will need to:
// - create a backend endpoint to handle the request
// - adapt the code below in your endpoint
const workos = new WorkOS(process.env.WORKOS_API_KEY);
export async function GET(request: Request) {
const url = new URL(request.url);
const code = url.searchParams.get('code') || '';
try {
const { user } = await workos.userManagement.authenticateWithCode({
clientId: process.env.WORKOS_CLIENT_ID || '',
code,
});
// Create a JWT with the user's information
// Here you might lookup and retrieve user details from your database
const token = await new SignJWT({ user })
.setProtectedHeader({ alg: 'HS256', typ: 'JWT' })
.setIssuedAt()
.setExpirationTime('1h')
.sign(getJwtSecretKey());
// Cleanup params
url.searchParams.delete('code');
// Store the session and redirect to the application
url.pathname = '/using-hosted-authkit/with-session';
const response = NextResponse.redirect(url);
response.cookies.set({
name: 'token',
value: token,
httpOnly: true,
path: '/',
secure: true,
sameSite: 'lax',
});
return response;
} catch (error) {
return NextResponse.json(error);
}
}
================================================
FILE: src/app/using-hosted-authkit/with-session/page.tsx
================================================
import { WorkOS } from '@workos-inc/node';
import { getUser, signOut } from './auth';
// This example uses Next.js with React Server Components.
// Because this page is an RSC, the code stays on the server, which allows
// us to use the WorkOS Node SDK without exposing our API key to the client.
//
// If your application is a single page app (SPA), you will need to:
// - create a form that can POST to an endpoint in your backend
// - call the `getAuthorizationURL` method in that endpoint
// - redirect the user to the returned URL
const workos = new WorkOS(process.env.WORKOS_API_KEY);
export default async function WithSession() {
const { isAuthenticated, user } = await getUser();
const authKitUrl = workos.userManagement.getAuthorizationUrl({
clientId: process.env.WORKOS_CLIENT_ID || '',
provider: 'authkit',
redirectUri: 'http://localhost:3000/using-hosted-authkit/with-session/callback',
});
return (
## Setup
First, ensure you have set up the [environment variables](/#environment-variables) and [redirects](/#redirects).
For 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**.
For 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.
## Examples
### Sign-up
- [Email + Password](./sign-up/email-password/page.tsx)
- [Magic Auth](./sign-up/magic-auth/page.tsx)
### Sign-in
- [Email + Password](./sign-in/email-password/page.tsx)
- [Magic Auth](./sign-in/magic-auth/page.tsx)
- [Google OAuth](./sign-in/google-oauth/page.tsx)
- [Microsoft OAuth](./sign-in/microsoft-oauth/page.tsx)
- [Single Sign-On](./sign-in/sso/page.tsx)
For 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.
You 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.
```bash
SSO_ENABLED_ORGANIZATION_ID=""
```
### Other
- [Multi-Factor Auth](./mfa/page.tsx)
- [Verify email](./verify-email/page.tsx)
- [Reset password](./reset-password/page.tsx)
- [Users table](./users-table/page.tsx)
- [Update user](./update-user/page.tsx)
================================================
FILE: src/app/using-your-own-ui/mfa/mfa.ts
================================================
'use server';
// These are Next.js server actions.
//
// If your application is a single page app (SPA) with a separate backend you will need to:
// - create a backend endpoint to handle each request
// - adapt the code below in each of those endpoints
//
// Please also note that for the sake of simplicity, we return all errors here.
// In a real application, you should pay attention to which errors make it
// to the client for security reasons.
import { WorkOS } from '@workos-inc/node';
const workos = new WorkOS(process.env.WORKOS_API_KEY);
export async function signIn(prevState: any, formData: FormData): Promise {
try {
// For the sake of simplicity, we directly return the user here.
// In a real application, you would probably store the user in a token (JWT)
// and store that token in your DB or use cookies.
return await workos.userManagement.authenticateWithPassword({
clientId: process.env.WORKOS_CLIENT_ID || '',
email: String(formData.get('email')),
password: String(formData.get('password')),
});
} catch (error) {
const err = JSON.parse(JSON.stringify(error));
if (err.rawData.code === 'mfa_enrollment') {
const { authenticationFactor, authenticationChallenge } =
await workos.userManagement.enrollAuthFactor({
userId: err.rawData.user.id,
type: 'totp',
totpIssuer: 'WorkOS',
totpUser: err.rawData.user.email,
});
return {
authenticationFactor,
authenticationChallenge,
pendingAuthenticationToken: err.rawData.pending_authentication_token,
};
}
if (err.rawData.code === 'mfa_challenge') {
const challenge = await workos.mfa.challengeFactor({
authenticationFactorId: err.rawData.authentication_factors[0].id,
});
return {
authenticationChallenge: challenge,
pendingAuthenticationToken: err.rawData.pending_authentication_token,
};
}
return { error: err };
}
}
export async function verifyTotp(prevState: any, formData: FormData) {
try {
// For the sake of simplicity, we directly return the user here.
// In a real application, you would probably store the user in a token (JWT)
// and store that token in your DB or use cookies.
return await workos.userManagement.authenticateWithTotp({
clientId: process.env.WORKOS_CLIENT_ID || '',
authenticationChallengeId: String(formData.get('authenticationChallengeId')),
pendingAuthenticationToken: String(formData.get('pendingAuthenticationToken')),
code: String(formData.get('code')),
});
} catch (error) {
return { error: JSON.parse(JSON.stringify(error)) };
}
}
type UnpackPromise = T extends Promise ? U : T;
type AuthenticateResponse = UnpackPromise<
ReturnType
>;
type EnrollResponse = UnpackPromise>;
type SignInResponse =
| AuthenticateResponse
| {
authenticationFactor?: EnrollResponse['authenticationFactor'];
authenticationChallenge: EnrollResponse['authenticationChallenge'];
pendingAuthenticationToken: string;
}
| { error: any };
================================================
FILE: src/app/using-your-own-ui/mfa/page.tsx
================================================
'use client';
import { useFormState } from 'react-dom';
import { signIn, verifyTotp } from './mfa';
import Image from 'next/image';
export default function Mfa() {
// This example uses Next.js server actions to call functions on the server side.
//
// If your application is a single page app (SPA), you will need to:
// - handle the form submission in `
`
// - make an API call to your backend (e.g using `fetch`)
const [sendResetState, sendResetAction] = useFormState(sendReset, { error: null });
const [resetPasswordState, resetPasswordAction] = useFormState(resetPassword, { error: null });
if (!token) {
return (
Reset password
{JSON.stringify(sendResetState, null, 2)}
);
}
return (
Reset password
{email && (
// We also include the email in a hidden input so that password managers can update the password on the correct account.
// https://developer.1password.com/docs/web/compatible-website-design/#password-change-and-reset-forms
)}
{JSON.stringify(resetPasswordState, null, 2)}
);
}
================================================
FILE: src/app/using-your-own-ui/reset-password/reset-password.ts
================================================
'use server';
// These are Next.js server actions.
//
// If your application is a single page app (SPA) with a separate backend you will need to:
// - create a backend endpoint to handle each request
// - adapt the code below in each of those endpoints
//
// Please also note that for the sake of simplicity, we return all errors here.
// In a real application, you should pay attention to which errors make it
// to the client for security reasons.
import { WorkOS } from '@workos-inc/node';
const workos = new WorkOS(process.env.WORKOS_API_KEY);
export async function sendReset(prevState: any, formData: FormData) {
try {
const email = String(formData.get('email'));
return await workos.userManagement.sendPasswordResetEmail({
email,
passwordResetUrl: `http://localhost:3000/using-your-own-ui/reset-password?email=${email}`,
});
} catch (error) {
return { error: JSON.parse(JSON.stringify(error)) };
}
}
export async function resetPassword(prevState: any, formData: FormData) {
try {
return await workos.userManagement.resetPassword({
newPassword: String(formData.get('newPassword')),
token: String(formData.get('token')),
});
} catch (error) {
return { error: JSON.parse(JSON.stringify(error)) };
}
}
================================================
FILE: src/app/using-your-own-ui/sign-in/email-password/email-password.ts
================================================
'use server';
// These are Next.js server actions.
//
// If your application is a single page app (SPA) with a separate backend you will need to:
// - create a backend endpoint to handle each request
// - adapt the code below in each of those endpoints
//
// Please also note that for the sake of simplicity, we return all errors here.
// In a real application, you should pay attention to which errors make it
// to the client for security reasons.
import { WorkOS } from '@workos-inc/node';
const workos = new WorkOS(process.env.WORKOS_API_KEY);
export async function signIn(prevState: any, formData: FormData) {
try {
// For the sake of simplicity, we directly return the user here.
// In a real application, you would probably store the user in a token (JWT)
// and store that token in your DB or use cookies.
return await workos.userManagement.authenticateWithPassword({
clientId: process.env.WORKOS_CLIENT_ID || '',
email: String(formData.get('email')),
password: String(formData.get('password')),
});
} catch (error) {
return { error: JSON.parse(JSON.stringify(error)) };
}
}
================================================
FILE: src/app/using-your-own-ui/sign-in/email-password/page.tsx
================================================
'use client';
import { useFormState } from 'react-dom';
import { signIn } from './email-password';
export default function SignInWithEmailPassword() {
// This example uses Next.js server actions to call functions on the server side.
//
// If your application is a single page app (SPA), you will need to:
// - handle the form submission in `
`
// - make an API call to your backend (e.g using `fetch`)
const [signInState, signInAction] = useFormState(signIn, { error: null });
return (
Sign-in
Email + Password
{JSON.stringify(signInState, null, 2)}
);
}
================================================
FILE: src/app/using-your-own-ui/sign-in/github-oauth/callback/route.ts
================================================
import { WorkOS } from '@workos-inc/node';
import { redirect } from 'next/navigation';
// This is a Next.js Route Handler.
//
// If your application is a single page app (SPA) with a separate backend you will need to:
// - create a backend endpoint to handle the request
// - adapt the code below in your endpoint
//
// Please also note that for the sake of simplicity, we directly return the user here in the query string.
// In a real application, you would probably store the user in a token (JWT)
// and store that token in your DB or use cookies.
const workos = new WorkOS(process.env.WORKOS_API_KEY);
export async function GET(request: Request) {
const code = new URL(request.url).searchParams.get('code') || '';
let response;
try {
response = await workos.userManagement.authenticateWithCode({
clientId: process.env.WORKOS_CLIENT_ID || '',
code,
});
} catch (error) {
response = error;
}
if (response) {
redirect(
`http://localhost:3000/using-your-own-ui/sign-in/github-oauth?response=${JSON.stringify(
response
)}`
);
}
}
================================================
FILE: src/app/using-your-own-ui/sign-in/github-oauth/page.tsx
================================================
import { WorkOS } from '@workos-inc/node';
// This example uses Next.js with React Server Components.
// Because this page is an RSC, the code stays on the server, which allows
// us to use the WorkOS Node SDK without exposing our API key to the client.
//
// If your application is a single page app (SPA), you will need to:
// - create a form that can POST to an endpoint in your backend
// - call the `getAuthorizationURL` method in that endpoint
// - redirect the user to the returned URL
const workos = new WorkOS(process.env.WORKOS_API_KEY);
export default function SignInWithGitHubOAuth({
searchParams,
}: {
searchParams: { [key: string]: string | string[] | undefined };
}) {
const githubOAuthUrl = workos.userManagement.getAuthorizationUrl({
clientId: process.env.WORKOS_CLIENT_ID || '',
provider: 'GitHubOAuth',
redirectUri: 'http://localhost:3000/using-your-own-ui/sign-in/github-oauth/callback',
});
const result = JSON.parse(String(searchParams.response ?? '{ "error": null }'));
return (
);
}
================================================
FILE: src/app/using-your-own-ui/sign-in/google-oauth/callback/route.ts
================================================
import { WorkOS } from '@workos-inc/node';
import { redirect } from 'next/navigation';
// This is a Next.js Route Handler.
//
// If your application is a single page app (SPA) with a separate backend you will need to:
// - create a backend endpoint to handle the request
// - adapt the code below in your endpoint
//
// Please also note that for the sake of simplicity, we directly return the user here in the query string.
// In a real application, you would probably store the user in a token (JWT)
// and store that token in your DB or use cookies.
const workos = new WorkOS(process.env.WORKOS_API_KEY);
export async function GET(request: Request) {
const code = new URL(request.url).searchParams.get('code') || '';
let response;
try {
response = await workos.userManagement.authenticateWithCode({
clientId: process.env.WORKOS_CLIENT_ID || '',
code,
});
} catch (error) {
response = error;
}
if (response) {
redirect(
`http://localhost:3000/using-your-own-ui/sign-in/google-oauth?response=${JSON.stringify(
response
)}`
);
}
}
================================================
FILE: src/app/using-your-own-ui/sign-in/google-oauth/page.tsx
================================================
import { WorkOS } from '@workos-inc/node';
// This example uses Next.js with React Server Components.
// Because this page is an RSC, the code stays on the server, which allows
// us to use the WorkOS Node SDK without exposing our API key to the client.
//
// If your application is a single page app (SPA), you will need to:
// - create a form that can POST to an endpoint in your backend
// - call the `getAuthorizationURL` method in that endpoint
// - redirect the user to the returned URL
const workos = new WorkOS(process.env.WORKOS_API_KEY);
export default function SignInWithGoogleOAuth({
searchParams,
}: {
searchParams: { [key: string]: string | string[] | undefined };
}) {
const googleOAuthUrl = workos.userManagement.getAuthorizationUrl({
clientId: process.env.WORKOS_CLIENT_ID || '',
provider: 'GoogleOAuth',
redirectUri: 'http://localhost:3000/using-your-own-ui/sign-in/google-oauth/callback',
});
const result = JSON.parse(String(searchParams.response ?? '{ "error": null }'));
return (
);
}
================================================
FILE: src/app/using-your-own-ui/sign-in/magic-auth/magic-auth.ts
================================================
'use server';
// These are Next.js server actions.
//
// If your application is a single page app (SPA) with a separate backend you will need to:
// - create a backend endpoint to handle each request
// - adapt the code below in each of those endpoints
//
// Please also note that for the sake of simplicity, we return all errors here.
// In a real application, you should pay attention to which errors make it
// to the client for security reasons.
import { WorkOS } from '@workos-inc/node';
const workos = new WorkOS(process.env.WORKOS_API_KEY);
export async function sendCode(prevState: any, formData: FormData) {
try {
return await workos.userManagement.sendMagicAuthCode({
email: String(formData.get('email')),
});
} catch (error) {
return { error: JSON.parse(JSON.stringify(error)) };
}
}
export async function signIn(prevState: any, formData: FormData) {
try {
// For the sake of simplicity, we directly return the user here.
// In a real application, you would probably store the user in a token (JWT)
// and store that token in your DB or use cookies.
return await workos.userManagement.authenticateWithMagicAuth({
clientId: process.env.WORKOS_CLIENT_ID || '',
code: String(formData.get('code')),
email: String(formData.get('email')),
});
} catch (error) {
return { error: JSON.parse(JSON.stringify(error)) };
}
}
================================================
FILE: src/app/using-your-own-ui/sign-in/magic-auth/page.tsx
================================================
'use client';
import * as React from 'react';
import { useFormState } from 'react-dom';
import { sendCode, signIn } from './magic-auth';
export default function SignInWithMagicAuth() {
// This example uses Next.js server actions to call functions on the server side.
//
// If your application is a single page app (SPA), you will need to:
// - handle the form submission in `
`
// - make an API call to your backend (e.g using `fetch`)
const [sendCodeState, sendCodeAction] = useFormState(sendCode, { error: null });
const [signInState, signInAction] = useFormState(signIn, { error: null });
const [email, setEmail] = React.useState('');
if (sendCodeState?.error === null) {
return (
Sign-in
Magic Auth
setEmail(event.target.value)}
/>
{JSON.stringify(sendCodeState, null, 2)}
);
}
return (
Sign-in
Magic Auth
{/* we need the email to authenticate with the code */}
{JSON.stringify(signInState, null, 2)}
);
}
================================================
FILE: src/app/using-your-own-ui/sign-in/microsoft-oauth/callback/route.ts
================================================
import { WorkOS } from '@workos-inc/node';
import { redirect } from 'next/navigation';
// This is a Next.js Route Handler.
//
// If your application is a single page app (SPA) with a separate backend you will need to:
// - create a backend endpoint to handle the request
// - adapt the code below in your endpoint
//
// Please also note that for the sake of simplicity, we directly return the user here in the query string.
// In a real application, you would probably store the user in a token (JWT)
// and store that token in your DB or use cookies.
const workos = new WorkOS(process.env.WORKOS_API_KEY);
export async function GET(request: Request) {
const code = new URL(request.url).searchParams.get('code') || '';
let response;
try {
response = await workos.userManagement.authenticateWithCode({
clientId: process.env.WORKOS_CLIENT_ID || '',
code,
});
} catch (error) {
response = error;
}
if (response) {
redirect(
`http://localhost:3000/using-your-own-ui/sign-in/microsoft-oauth?response=${JSON.stringify(
response
)}`
);
}
}
================================================
FILE: src/app/using-your-own-ui/sign-in/microsoft-oauth/page.tsx
================================================
import { WorkOS } from '@workos-inc/node';
// This example uses Next.js with React Server Components.
// Because this page is an RSC, the code stays on the server, which allows
// us to use the WorkOS Node SDK without exposing our API key to the client.
//
// If your application is a single page app (SPA), you will need to:
// - create a form that can POST to an endpoint in your backend
// - call the `getAuthorizationURL` method in that endpoint
// - redirect the user to the returned URL
const workos = new WorkOS(process.env.WORKOS_API_KEY);
export default function SignInWithMicrosoftOAuth({
searchParams,
}: {
searchParams: { [key: string]: string | string[] | undefined };
}) {
const microsoftOAuthUrl = workos.userManagement.getAuthorizationUrl({
clientId: process.env.WORKOS_CLIENT_ID || '',
provider: 'MicrosoftOAuth',
redirectUri: 'http://localhost:3000/using-your-own-ui/sign-in/microsoft-oauth/callback',
});
const result = JSON.parse(String(searchParams.response ?? '{ "error": null }'));
return (
);
}
================================================
FILE: src/app/using-your-own-ui/sign-in/sso/callback/route.ts
================================================
import { WorkOS } from '@workos-inc/node';
import { redirect } from 'next/navigation';
// This is a Next.js Route Handler.
//
// If your application is a single page app (SPA) with a separate backend you will need to:
// - create a backend endpoint to handle the request
// - adapt the code below in your endpoint
//
// Please also note that for the sake of simplicity, we directly return the user here in the query string.
// In a real application, you would probably store the user in a token (JWT)
// and store that token in your DB or use cookies.
const workos = new WorkOS(process.env.WORKOS_API_KEY);
export async function GET(request: Request) {
const code = new URL(request.url).searchParams.get('code') || '';
let response;
try {
response = await workos.userManagement.authenticateWithCode({
clientId: process.env.WORKOS_CLIENT_ID || '',
code,
});
} catch (error) {
response = error;
}
if (response) {
redirect(
`http://localhost:3000/using-your-own-ui/sign-in/sso?response=${JSON.stringify(response)}`
);
}
}
================================================
FILE: src/app/using-your-own-ui/sign-in/sso/page.tsx
================================================
import { WorkOS } from '@workos-inc/node';
// This example uses Next.js with React Server Components.
// Because this page is an RSC, the code stays on the server, which allows
// us to use the WorkOS Node SDK without exposing our API key to the client.
//
// If your application is a single page app (SPA), you will need to:
// - create a form that can POST to an endpoint in your backend
// - call the `getAuthorizationURL` method in that endpoint
// - redirect the user to the returned URL
const workos = new WorkOS(process.env.WORKOS_API_KEY);
export default function SignInWithSSO({
searchParams,
}: {
searchParams: { [key: string]: string | string[] | undefined };
}) {
const ssoUrl = workos.userManagement.getAuthorizationUrl({
clientId: process.env.WORKOS_CLIENT_ID || '',
organizationId: process.env.SSO_ENABLED_ORGANIZATION_ID || '',
redirectUri: 'http://localhost:3000/using-your-own-ui/sign-in/sso/callback',
});
const result = JSON.parse(String(searchParams.response ?? '{ "error": null }'));
return (
);
}
================================================
FILE: src/app/using-your-own-ui/sign-up/email-password/email-password.ts
================================================
'use server';
// These are Next.js server actions.
//
// If your application is a single page app (SPA) with a separate backend you will need to:
// - create a backend endpoint to handle each request
// - adapt the code below in each of those endpoints
//
// Please also note that for the sake of simplicity, we return all errors here.
// In a real application, you should pay attention to which errors make it
// to the client for security reasons.
import { WorkOS } from '@workos-inc/node';
const workos = new WorkOS(process.env.WORKOS_API_KEY);
export async function signUp(prevState: any, formData: FormData) {
try {
// For the sake of simplicity, we directly return the user here.
// In a real application, you would probably redirect the user to sign-in.
return await workos.userManagement.createUser({
email: String(formData.get('email')),
password: String(formData.get('password')),
firstName: String(formData.get('firstName')),
lastName: String(formData.get('lastName')),
});
} catch (error) {
return { error: JSON.parse(JSON.stringify(error)) };
}
}
================================================
FILE: src/app/using-your-own-ui/sign-up/email-password/page.tsx
================================================
'use client';
import { useFormState } from 'react-dom';
import { signUp } from './email-password';
export default function SignUpWithEmailPassword() {
// This example uses Next.js server actions to call functions on the server side.
//
// If your application is a single page app (SPA), you will need to:
// - handle the form submission in `
`
// - make an API call to your backend (e.g using `fetch`)
const [signUpState, signUpAction] = useFormState(signUp, { error: null });
return (
Sign-up
Email + Password
{JSON.stringify(signUpState, null, 2)}
);
}
================================================
FILE: src/app/using-your-own-ui/sign-up/magic-auth/magic-auth.ts
================================================
'use server';
// These are Next.js server actions.
//
// If your application is a single page app (SPA) with a separate backend you will need to:
// - create a backend endpoint to handle each request
// - adapt the code below in each of those endpoints
//
// Please also note that for the sake of simplicity, we return all errors here.
// In a real application, you should pay attention to which errors make it
// to the client for security reasons.
import { WorkOS } from '@workos-inc/node';
const workos = new WorkOS(process.env.WORKOS_API_KEY);
export async function signUp(prevState: any, formData: FormData) {
try {
// For the sake of simplicity, we directly return the user here.
// In a real application, you would probably send a magic code email
// and redirect the user to a page where they can enter the code.
// See the `sign-in/magic-auth` example for more details.
return await workos.userManagement.createUser({
email: String(formData.get('email')),
password: undefined,
firstName: String(formData.get('firstName')),
lastName: String(formData.get('lastName')),
});
} catch (error) {
return { error: JSON.parse(JSON.stringify(error)) };
}
}
================================================
FILE: src/app/using-your-own-ui/sign-up/magic-auth/page.tsx
================================================
'use client';
import { useFormState } from 'react-dom';
import { signUp } from './magic-auth';
export default function SignUpWithMagicAuth() {
// This example uses Next.js server actions to call functions on the server side.
//
// If your application is a single page app (SPA), you will need to:
// - handle the form submission in `
`
// - make an API call to your backend (e.g using `fetch`)
const [signUpState, signUpAction] = useFormState(signUp, { error: null });
return (
Sign-up
Magic Auth
{JSON.stringify(signUpState, null, 2)}
);
}
================================================
FILE: src/app/using-your-own-ui/update-user/page.tsx
================================================
'use client';
import { useFormState } from 'react-dom';
import { getUser, updateUser } from './update-user';
export default function UpdateUser() {
// This example uses Next.js server actions to call functions on the server side.
//
// If your application is a single page app (SPA), you will need to:
// - handle the form submission in `
`
// - make an API call to your backend (e.g using `fetch`)
const [getUserState, getUserAction] = useFormState(getUser, { error: null });
const [updateUserState, updateUserAction] = useFormState(updateUser, { error: null });
if (!('user' in getUserState)) {
return (
Update user
{JSON.stringify(getUserState, null, 2)}
);
}
return (
Update user
{JSON.stringify(updateUserState, null, 2)}
);
}
================================================
FILE: src/app/using-your-own-ui/update-user/update-user.ts
================================================
'use server';
// These are Next.js server actions.
//
// If your application is a single page app (SPA) with a separate backend you will need to:
// - create a backend endpoint to handle each request
// - adapt the code below in each of those endpoints
//
// Please also note that for the sake of simplicity, we return all errors here.
// In a real application, you should pay attention to which errors make it
// to the client for security reasons.
import { WorkOS } from '@workos-inc/node';
import type { User } from '@workos-inc/node';
import { revalidatePath } from 'next/cache';
const workos = new WorkOS(process.env.WORKOS_API_KEY);
export async function getUser(prevState: any, formData: FormData): Promise {
try {
const users = await workos.userManagement.listUsers({ email: String(formData.get('email')) });
const user = users.data[0];
return { user };
} catch (error) {
return { error: JSON.parse(JSON.stringify(error)) };
}
}
export async function updateUser(prevState: any, formData: FormData): Promise {
try {
const user = await workos.userManagement.updateUser({
userId: String(formData.get('userId')),
firstName: String(formData.get('firstName')),
lastName: String(formData.get('lastName')),
});
revalidatePath('/users-table');
return { user };
} catch (error) {
return { error: JSON.parse(JSON.stringify(error)) };
}
}
type Response = { user: User } | { error: any };
================================================
FILE: src/app/using-your-own-ui/users-table/loading.tsx
================================================
export default function Loading() {
return (
Users
Email
Name
Verified
{Array.from({ length: 3 }, (_, i) => (
…
…
…
))}
);
}
================================================
FILE: src/app/using-your-own-ui/users-table/page.tsx
================================================
import { WorkOS } from '@workos-inc/node';
import type { User } from '@workos-inc/node';
import Link from 'next/link';
import { deleteUser } from './users-table';
// This example uses Next.js with React Server Components.
// Because this page is an RSC, the code stays on the server, which allows
// us to use the WorkOS Node SDK without exposing our API key to the client.
//
// If your application is a single page app (SPA), you will need to:
// - create a backend endpoint to return the list of users
// - adapt the code below in your endpoint
// - make an API call to your backend (e.g using `fetch`)
const workos = new WorkOS(process.env.WORKOS_API_KEY);
export default async function UsersTable({
searchParams,
}: {
searchParams: { before?: string; after?: string };
}) {
const users = await workos.userManagement.listUsers({ limit: 5, ...searchParams });
const { before, after } = users.listMetadata;
return (
Users
Email
Name
Verified
{users.data.map((user) => (
{user.email}
{formatName(user)}
{user.emailVerified ? 'Yes' : 'No'}
))}
);
}
function formatName(user: User) {
if (user.firstName && user.lastName) {
return `${user.firstName} ${user.lastName}`;
} else {
return user.lastName ?? user.firstName ?? '';
}
}
================================================
FILE: src/app/using-your-own-ui/users-table/users-table.ts
================================================
'use server';
// These are Next.js server actions.
//
// If your application is a single page app (SPA) with a separate backend you will need to:
// - create a backend endpoint to handle each request
// - adapt the code below in each of those endpoints
//
// Please also note that for the sake of simplicity, we return all errors here.
// In a real application, you should pay attention to which errors make it
// to the client for security reasons.
import { WorkOS } from '@workos-inc/node';
import { revalidatePath } from 'next/cache';
const workos = new WorkOS(process.env.WORKOS_API_KEY);
export async function deleteUser(formData: FormData) {
try {
await workos.userManagement.deleteUser(String(formData.get('userId')));
revalidatePath('/users-table');
} catch (error) {
console.log(error);
}
}
================================================
FILE: src/app/using-your-own-ui/verify-email/page.tsx
================================================
'use client';
import { useFormState } from 'react-dom';
import { sendCode, verifyEmail } from './verify-email';
export default function VerifyEmail() {
// This example uses Next.js server actions to call functions on the server side.
//
// If your application is a single page app (SPA), you will need to:
// - handle the form submission in `
`
// - make an API call to your backend (e.g using `fetch`)
const [sendCodeState, sendCodeAction] = useFormState(sendCode, { error: null });
const [verifyEmailState, verifyEmailAction] = useFormState(verifyEmail, { error: null });
if (!('user' in sendCodeState)) {
return (
Verify email
{JSON.stringify(sendCodeState, null, 2)}
);
}
return (
Verify email
{JSON.stringify(verifyEmailState, null, 2)}
);
}
================================================
FILE: src/app/using-your-own-ui/verify-email/verify-email.ts
================================================
'use server';
// These are Next.js server actions.
//
// If your application is a single page app (SPA) with a separate backend you will need to:
// - create a backend endpoint to handle each request
// - adapt the code below in each of those endpoints
//
// Please also note that for the sake of simplicity, we return all errors here.
// In a real application, you should pay attention to which errors make it
// to the client for security reasons.
import { WorkOS } from '@workos-inc/node';
import { revalidatePath } from 'next/cache';
const workos = new WorkOS(process.env.WORKOS_API_KEY);
export async function sendCode(prevState: any, formData: FormData) {
try {
const users = await workos.userManagement.listUsers({ email: String(formData.get('email')) });
const user = users.data[0];
return await workos.userManagement.sendVerificationEmail({ userId: user.id });
} catch (error) {
return { error: JSON.parse(JSON.stringify(error)) };
}
}
export async function verifyEmail(prevState: any, formData: FormData) {
try {
const response = await workos.userManagement.verifyEmail({
userId: String(formData.get('userId')),
code: String(formData.get('code')),
});
revalidatePath('/users-table');
return response;
} catch (error) {
return { error: JSON.parse(JSON.stringify(error)) };
}
}
================================================
FILE: src/middleware.ts
================================================
// This file is only used in conjunction with the authkit-nextjs library
import { authkitMiddleware } from '@workos-inc/authkit-nextjs';
export default authkitMiddleware({ debug: true });
// Match against pages that require auth, e.g.:
export const config = { matcher: ['/using-hosted-authkit/with-nextjs'] };
================================================
FILE: tsconfig.json
================================================
{
"compilerOptions": {
"target": "es5",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
"strict": true,
"noEmit": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "bundler",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve",
"incremental": true,
"plugins": [
{
"name": "next"
}
],
"paths": {
"@/*": ["./src/*"]
}
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
"exclude": ["node_modules"]
}