Skip to content

Commit

Permalink
Merge branch 'main' into aa/DOCS-9560
Browse files Browse the repository at this point in the history
  • Loading branch information
victoriaxyz authored Dec 2, 2024
2 parents 31bca10 + d2a4e67 commit 3135e4e
Show file tree
Hide file tree
Showing 20 changed files with 725 additions and 60 deletions.
20 changes: 20 additions & 0 deletions docs/_partials/reverification-route-handler.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
The following example uses the [`has()`](/docs/references/nextjs/auth-object#has) helper to check if the user has verified their credentials within a specific time period. The `strict` configuration sets the time period to 10 minutes. If the user hasn't verified their credentials within 10 minutes, the `reverificationErrorResponse` utility is used to return an error.

```tsx {{ filename: 'app/api/reverification-example/route.ts' }}
import { auth, reverificationErrorResponse } from '@clerk/nextjs/server'

export const POST = async (req: Request) => {
const { has } = await auth()

// Check if the user has *not* verified their credentials within the past 10 minutes.
const shouldUserRevalidate = !has({ reverification: 'strict' })

// If the user hasn't reverified, return an error with the matching configuration (e.g., `strict`)
if (shouldUserRevalidate) {
return reverificationErrorResponse('strict')
}

// If the user has verified credentials, return a successful response
return new Response({ success: true })
}
```
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
> [!CAUTION]
> The entire session token has a max size of 4kb. Exceeding this size can have adverse effects, including a possible infinite redirect loop for users who exceed this size in Next.js applications.
> It's recommended to move particularly large claims out of the JWT and fetch these using a separate API call from your backend.
> [Learn more](/docs/backend-requests/resources/cookie-size-limits).
> [Learn more](/docs/backend-requests/resources/session-tokens#size-limitations).
2 changes: 1 addition & 1 deletion docs/backend-requests/making/custom-session-token.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ By default, session tokens contain claims that are required for Clerk to functio

This guide will show you how to customize a session token to include additional claims that you may need in your application.

<Include src="_partials/cookie-size-callout" />
<Include src="_partials/token-size-callout" />

{/* TODO: Update the H3 to an H2 when the Steps component can accept headings other than H3. */}

Expand Down
2 changes: 1 addition & 1 deletion docs/backend-requests/making/jwt-templates.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ Clerk offers the ability to generate [JSON Web Tokens](https://en.wikipedia.org/

You can control the claims that will go into these tokens by creating custom **JWT Templates** that fit your needs. This enables you to integrate with any third-party services that support authentication with JWTs. An example use case is integrating with a third-party service that is able to consume JWTs, but requires them to be in a particular format.

<Include src="_partials/cookie-size-callout" />
<Include src="_partials/token-size-callout" />

## What is a JWT template?

Expand Down
12 changes: 0 additions & 12 deletions docs/backend-requests/resources/cookie-size-limits.mdx

This file was deleted.

18 changes: 18 additions & 0 deletions docs/backend-requests/resources/session-tokens.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ description: Learn about session tokens and how to validate them in your backend

When a user is authenticated in your application, Clerk generates a short-lived session token that you can use to authenticate requests to your backend. This token is a JSON Web Token (JWT) that contains information about the user and their session.

Learn more about how Clerk combines session token authentication and JWT authentication in the [blog post](https://clerk.com/blog/combining-the-benefits-of-session-tokens-and-jwts).

## Default session claims

Every generated token has default claims that cannot be overridden by templates. Clerk's default claims include:
Expand Down Expand Up @@ -32,6 +34,22 @@ If you would like to add custom claims to your session token, you can [customize

You can also create custom tokens using a [JWT template](/docs/backend-requests/making/jwt-templates).

## Size limitations

The Clerk session token is stored in a cookie. All modern browsers [limit the maximum size of a cookie to 4kb](https://datatracker.ietf.org/doc/html/rfc2109#section-6.3). Exceeding this limit can have adverse effects, including a possible infinite redirect loop for users who exceed this size in Next.js applications.

A session token with the [default session claims](#default-session-claims) won't run into this issue, as this configuration produces a cookie significantly smaller than 4kb. However, this limitation becomes relevant when implementing a [custom session token](/docs/backend-requests/making/custom-session-token) or creating a [custom JWT template](/docs/backend-requests/making/jwt-templates). In these cases, it's recommended to move particularly large claims out of the token and fetch these using a separate API call from your backend.

Claims to monitor for size limits:

- `user.organizations`
- `user.public_metadata`
- `user.unsafe_metadata`
- `org.public_metadata`
- `org_membership.public_metadata`

If you include any of these claims in your token, use caution to ensure the stored data doesn't exceed the size limit.

## Validate session tokens

If you're using the middleware provided by our Clerk SDKs, this is all handled automatically in every request. If you're not using the middleware, you can still use the respective helpers provided by the SDKs to validate the tokens.
Expand Down
8 changes: 8 additions & 0 deletions docs/backend-requests/versioning/available-versions.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,14 @@ description: A list of the available API versions and their breaking changes.

Below is a list of all the available API versions with their respective breaking changes.

### 2024-10-01

- Notification for new sign-ins to users' accounts feature becomes available.
- The response for sign-ins with an email address that matches a **SAML connection** is updated:
- Instead of responding with a status of `needs_identifier`, the API now returns a status of `needs_first_factor`.
- The email address that matched will be returned in the identifier field.
- The only strategy that will be included in supported first factors is `enterprise_sso`.

### 2021-02-05

The initial API version was released on 2021-02-05 as part of the first Clerk release. It predates the versioning system. All changes made to it since then are backwards compatible.
2 changes: 1 addition & 1 deletion docs/components/control/signed-in.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ The `<SignedIn>` component offers authentication checks as a cross-cutting conce
Below is an example of how to use `<SignedIn>` with React Router. The `<SignedIn>` component can be used as a child of a `<Route />` component to render content only to signed in users.

```tsx {{ filename: 'app.tsx' }}
import { Routes, Route } from 'react-router-dom'
import { Routes, Route } from 'react-router'
import { ClerkProvider, SignedIn } from '@clerk/clerk-react'

function App() {
Expand Down
2 changes: 1 addition & 1 deletion docs/components/control/signed-out.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ The `<SignedOut>` component offers authentication checks as a cross-cutting conc
Below is an example of how to use `<SignedOut>` with React Router. The `<SignedOut>` component can be used as a child of a `<Route />` component to render content only to signed in users.

```tsx {{ filename: 'app.tsx' }}
import { Routes, Route } from 'react-router-dom'
import { Routes, Route } from 'react-router'
import { ClerkProvider, SignedOut, RedirectToSignIn } from '@clerk/clerk-react'

function App() {
Expand Down
2 changes: 1 addition & 1 deletion docs/custom-flows/email-password-mfa.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ This guide will walk you through how to build a custom email/password sign-in fl
<Tabs type="framework" items={["Next.js", "JavaScript", "Expo", "iOS (Beta)"]}>
<Tab>
```tsx {{ filename: 'app/sign-in/[[...sign-in]].tsx', collapsible: true }}
```tsx {{ filename: 'app/sign-in/[[...sign-in]]/page.tsx', collapsible: true }}
'use client'

import * as React from 'react'
Expand Down
4 changes: 2 additions & 2 deletions docs/custom-flows/email-password.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ This guide will walk you through how to build a custom email/password sign-up an
<Tab>
This example is written for Next.js App Router but it can be adapted for any React meta framework, such as Remix.

```tsx {{ filename: '/app/sign-up/[[...sign-up]].tsx', collapsible: true }}
```tsx {{ filename: '/app/sign-up/[[...sign-up]]/page.tsx', collapsible: true }}
'use client'

import * as React from 'react'
Expand Down Expand Up @@ -493,7 +493,7 @@ This guide will walk you through how to build a custom email/password sign-up an
<Tab>
This example is written for Next.js App Router but it can be adapted for any React meta framework, such as Remix.

```tsx {{ filename: '/app/sign-in/[[...sign-in]].tsx', collapsible: true }}
```tsx {{ filename: '/app/sign-in/[[...sign-in]]/page.tsx', collapsible: true }}
'use client'

import * as React from 'react'
Expand Down
202 changes: 202 additions & 0 deletions docs/guides/reverification.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,202 @@
---
title: Add reverification for sensitive actions
description: Learn how to implement Clerk's reverification feature to protect sensitive actions in your application.
---

> [!WARNING]
> This feature is currently in public beta. **It is not recommended for production use**.
>
> Depending on the SDK you're using, this feature requires `@clerk/[email protected]` or later, `@clerk/[email protected]` or later, and `@clerk/[email protected]` or later.
Reverification allows you to prompt a user to verify their credentials before performing sensitive actions, even if they're already authenticated. For example, in a banking application, transferring money is considered a "sensitive action." Reverification can be used to confirm the user's identity.

## How to require reverification

To implement reverification, you need to handle it both on the server- and client-side.

### Handle reverification server-side

To handle reverification server-side, use the [`auth.has()`](/docs/references/nextjs/auth-object#has) helper to check if the user has verified their credentials within a specific time period. Pass a [configuration](#supported-verification-configurations) to set the time period you would like. If the user hasn't verified their credentials within that time period, return either `reverificationError` or `reverificationErrorResponse`, depending on the framework you're using. Use the following tabs to see examples for different frameworks.

<Tabs items={["Next.js Server Action", "Next.js Route Handler", "Ruby on Rails", "Other"]}>
<Tab>
The following example uses the [`has()`](/docs/references/nextjs/auth-object#has) helper to check if the user has verified their credentials within a specific time period. The `strict` configuration sets the time period to 10 minutes. If the user hasn't verified their credentials within 10 minutes, the `reverificationError` utility is used to return an error.

```ts {{ filename: '/app/actions.ts' }}
'use server'

import { auth, reverificationError } from '@clerk/nextjs/server'

export const myAction = async () => {
const { has } = await auth.protect()

// Check if the user has *not* verified their credentials within the past 10 minutes
const shouldUserRevalidate = !has({ reverification: 'strict' })

// If the user hasn't reverified, return an error with the matching configuration (e.g. `strict`)
if (shouldUserRevalidate) {
return reverificationError('strict')
}

// If the user has verified credentials, return a successful response
return { success: true }
}
```
</Tab>

<Tab>
<Include src="_partials/reverification-route-handler" />
</Tab>

<Tab>
The following example uses the `clerk_user_needs_reverification` helper to check if the user has verified their credentials within a specific time period. The `moderate` configuration sets the time period to 1 hour. If the user hasn't verified their credentials within 1 hour, the `clerk_render_reverification` utility is used to return a `403 forbidden` error that the client reads to initiate the reverification flow. Once the user completes the reverification on the client-side, they can access the `foo` action, which returns a success response.

```ruby {{ filename: 'app/controllers/home_controller.rb' }}
class HomeController < ApplicationController
before_action :require_reverification, only: :foo

def foo
render json: { success: "true" }
end

private

# will halt the request and respond with a JSON that Clerk.js
# will read and kickstart a reverification flow
def require_reverification
clerk_render_reverification(Clerk::StepUp::PRESETS[:moderate]) if clerk_user_needs_reverification?(Clerk::StepUp::PRESETS[:moderate])
end
end
```
</Tab>

<Tab>
> [!WARNING]
> `reverificationErrorResponse` and `reverificationError` requires `@clerk/[email protected]` or later, and `@clerk/[email protected]` or later.
- For a JavaScript or Typescript framework that supports the [Fetch API `Response`](https://developer.mozilla.org/en-US/docs/Web/API/Response), use the `reverificationErrorResponse` to trigger reverification. For example:
<CodeBlockTabs options={["Astro"]}>
```typescript {{ filename: 'src/api/reverification-example.ts' }}
import type { APIRoute } from 'astro'
import { reverificationErrorResponse } from '@clerk/shared/authorization-errors'

export const GET: APIRoute = async ({ locals }) => {
const { has } = locals.auth()

// Check if the user has *not* verified their credentials within the past 10 minutes
const shouldUserRevalidate = !has({ reverification: 'strict' })

// If the user hasn't reverified, return an error with the matching configuration (e.g. `strict`)
if (shouldUserRevalidate) {
return reverificationErrorResponse('strict')
}

return new Response('success', { status: 200 })
}
```
</CodeBlockTabs>
- For a JavaScript or Typescript framework that provides its own utilities to handle responses, use `reverificationError`. For example:
<CodeBlockTabs options={["Hono"]}>
```typescript {{ filename: 'src/api/hello.ts' }}
import { Hono } from 'hono'

const app = new Hono()

// POST request route
app.post('/api/hello', async (c) => {
return c.json(reverificationError('strict'))
})
```
</CodeBlockTabs>
- Alternatively, if you're not using JavaScript or TypeScript, you can create a custom helper that returns the following JSON response (it's recommended to use a `403 Forbidden` status code in your response):
```json
{
"clerk_error": {
"type": "forbidden",
"reason": "reverification-error"
}
}
```
</Tab>
</Tabs>

### Handle reverification client-side

After setting up reverification on the server-side, you must handle reverification on the client-side.

The following example demonstrates how to use the [`useReverification()`](/docs/references/react/use-reverification) hook to detect authorization errors and automatically display a modal that allows the user to verify their identity. Upon successful verification, the previously failed request is automatically retried.

<Tabs items={["Next.js Server Action", "Next.js Route Handler", "React"]}>
<Tab>
```tsx {{ filename: '/app/perform-action/page.tsx' }}
'use client'

import { useReverification } from '@clerk/nextjs'
import { myAction } from '../actions'

export default function Page() {
const [performAction] = useReverification(myAction)

const handleClick = async () => {
const myData = await performAction()
// If `myData` is null, the user cancelled the reverification process
// You can choose how your app responds. This example returns null.
if (!myData) return
}

return <button onClick={handleClick}>Perform action</button>
}
```
</Tab>

<Tab>
```tsx {{ filename: '/app/transfer/page.tsx' }}
'use client'

import { useReverification } from '@clerk/nextjs'

export default function Page({ amount_in_cents }: { amount_in_cents: number }) {
const [transferMoney] = useReverification(
async () =>
await fetch('/api/reverification-example', {
method: 'POST',
body: JSON.stringify({ amount_in_cents }),
}),
)

return <button onClick={transferMoney}>Transfer</button>
}
```
</Tab>

<Tab>
```tsx {{ filename: '/src/components/TransferButton.js' }}
import { useReverification } from '@clerk/react'

export function TransferButton({ amount_in_cents }: { amount_in_cents: number }) {
const [transferMoney] = useReverification(() =>
fetch('/api/reverification-example', {
method: 'POST',
body: JSON.stringify({ amount_in_cents }),
}),
)

return <button onClick={transferMoney}>Transfer</button>
}
```
</Tab>
</Tabs>

## Supported reverification configurations

To define the time period of the reverification check, you can pass the one of the following configurations to the `has()` helper: `strict_mfa`, `strict`, `moderate`, and `lax`. See the [`has()` reference doc](/docs/references/nextjs/auth-object#check-authorization-params-with-custom-permissions) for more details.

## Caveats

Before enabling this feature, consider the following:

1. **Available factors for reverification**: Not all authentication factors are supported for reverification. The available options are:
- First factors: password, email code, phone code
- Second factors: phone code, authenticator app, backup code
1. **Graceful downgrade of verification level**: If you request a `second_factor` or `multi_factor` level of verification but the user lacks a second factor available, the utilities automatically downgrade the requested level to `first_factor`.
1. **Eligibility for sensitive actions**: Users without any of the above factors cannot reverify. This can be an issue for apps that don't require email addresses to sign up or have disabled email codes in favor of email links.
Loading

0 comments on commit 3135e4e

Please sign in to comment.