Skip to content

Commit

Permalink
(/guides/reverification): improve "Other" tab in "How to require reve…
Browse files Browse the repository at this point in the history
…rification" (#1745)

Co-authored-by: Alexis Aguilar <[email protected]>
  • Loading branch information
panteliselef and alexisintech authored Nov 26, 2024
1 parent ca8e9b0 commit edd0c56
Show file tree
Hide file tree
Showing 2 changed files with 96 additions and 67 deletions.
2 changes: 1 addition & 1 deletion docs/_partials/reverification-route-handler.mdx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
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 and initiate the session reverification flow on the client-side.
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'
Expand Down
161 changes: 95 additions & 66 deletions docs/guides/reverification.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,21 @@ Reverification allows you to prompt a user to verify their credentials before pe

## How to require reverification

To reduce the risk of unauthorized access to a user's account during sensitive actions, you can periodically require users to reverify their active session by confirming their credentials. Reverification is triggered by implementing a check in your backend.
To implement reverification, you need to handle it both on the server- and client-side.

<Tabs items={["Next.js Server Action", "Next.js Route Handler", "Ruby & React", "Other"]}>
### 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.

> [!WARNING]
> `reverificationErrorResponse` and `reverificationError` requires `@clerk/[email protected]` or later, and `@clerk/[email protected]` or later.
<Tabs items={["Next.js Server Action", "Next.js Route Handler", "Ruby", "Other"]}>
<Tab>
### Handle reverification server-side
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.

The following example uses the [`has()`](/docs/references/nextjs/auth#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.
> [!NOTE]
> Next.js Server Actions use `reverificationError` instead of `reverificationErrorResponse` as they need to return a serializable object. A serializable object refers to data that can be safely converted to a JSON format for transmission between the server and client.
```ts {{ filename: '/app/actions.ts' }}
'use server'
Expand All @@ -40,13 +48,89 @@ To reduce the risk of unauthorized access to a user's account during sensitive a
return { success: true }
}
```
</Tab>

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

<Tab>
In your controller, add a filter that leverages the new helpers.

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

### Handle reverification client-side
<Tab>
- 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.
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.
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'

Expand All @@ -69,24 +153,14 @@ To reduce the risk of unauthorized access to a user's account during sensitive a
</Tab>

<Tab>
### Handle reverification server-side

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

### 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.

```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(() =>
fetch('/api/transfer-balance', {
fetch('/api/reverification-example', {
method: 'POST',
body: JSON.stringify({ amount_in_cents }),
}),
Expand All @@ -98,39 +172,12 @@ To reduce the risk of unauthorized access to a user's account during sensitive a
</Tab>

<Tab>
### Handle reverification server-side

In your controller add a filter that leverages the new helpers

```ruby
# app/controllers/home_controller.rb
class HomeController < ApplicationController
before_action :require_reverification, only: :foo

def foo
render json: { sucess: "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
```

### Handle reverification client-side

In your React application you can wrap your fetcher with `useReverification()`.

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

export function TransferButton({ amount_in_cents }) {
export function TransferButton({ amount_in_cents }: { amount_in_cents: number }) {
const [transferMoney] = useReverification(() =>
fetch('/api/transfer-balance', {
fetch('/api/reverification-example', {
method: 'POST',
body: JSON.stringify({ amount_in_cents }),
}),
Expand All @@ -140,24 +187,6 @@ To reduce the risk of unauthorized access to a user's account during sensitive a
}
```
</Tab>

<Tab>
> [!NOTE]
> `reverificationMismatchResponse` requires `@clerk/[email protected]` or later, and `@clerk/[email protected]` or later.
You can use the `reverificationMismatchResponse` exported from `@clerk/shared/authorization-errors`. If you're not using JavaScript or TypeScript, you can create a custom helper that returns the following JSON response:

```json
{
"clerk_error": {
"type": "forbidden",
"reason": "reverification-mismatch"
}
}
```

It's recommended to use a `403 Forbidden` status code in your response.
</Tab>
</Tabs>

## Supported reverification configurations
Expand Down

0 comments on commit edd0c56

Please sign in to comment.