Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(nuxt): Add Nuxt SDK docs #1728

Merged
merged 26 commits into from
Dec 19, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
e7459ad
feat(nuxt): Add initial quickstart and reference docs
wobsoriano Nov 16, 2024
a68f129
chore: More nuxt SDK docs updates
wobsoriano Nov 20, 2024
04a8b09
docs(nuxt): Add clerkMiddleware reference
wobsoriano Nov 20, 2024
e679860
docs(nuxt): Add clerkMiddleware link to quickstart
wobsoriano Nov 20, 2024
b78489d
docs(nuxt): Add route middleware example
wobsoriano Nov 20, 2024
7bc65ed
docs(nuxt): Add clerkMiddleware reference to overview
wobsoriano Nov 20, 2024
026108a
docs(nuxt): Add quickstart overview and homepage entry
wobsoriano Nov 20, 2024
a81cc4a
add placeholder icon
wobsoriano Nov 20, 2024
317f0a2
add nuxt svgs
wobsoriano Nov 20, 2024
b180c9b
docs(nuxt): Add backend references for clerkClient
wobsoriano Nov 20, 2024
d189d22
docs(nuxt): Add missing async keyword
wobsoriano Nov 20, 2024
feb1463
make nuxt icon a bit bigger
bradlc Nov 21, 2024
47e4bc6
docs(nuxt): Fix example for protecting pages
wobsoriano Nov 21, 2024
0fbe641
docs(nuxt): Add link to creating a Nuxt app
wobsoriano Nov 21, 2024
162d9f2
Update protecting-pages.mdx
wobsoriano Nov 25, 2024
6cc2acd
fix conflicts
wobsoriano Dec 13, 2024
07f5bd9
docs(nuxt): Replace express with nuxt
wobsoriano Dec 13, 2024
9b1ea2c
fix links
wobsoriano Dec 15, 2024
ab341dc
Merge branch 'rob/eco-224-vue-sdk-references' into rob/eco-224-nuxt-q…
wobsoriano Dec 15, 2024
028b4be
Merge branch 'rob/eco-224-vue-sdk-references' into rob/eco-224-nuxt-q…
wobsoriano Dec 16, 2024
ad7a401
Merge branch 'rob/eco-224-vue-sdk-references' into rob/eco-224-nuxt-q…
victoriaxyz Dec 16, 2024
f70089d
Merge branch 'rob/eco-224-vue-sdk-references' into rob/eco-224-nuxt-q…
victoriaxyz Dec 17, 2024
4fb15b5
update
victoriaxyz Dec 18, 2024
ff4bded
Merge branch 'rob/eco-224-vue-sdk-references' into rob/eco-224-nuxt-q…
victoriaxyz Dec 18, 2024
50e5073
docs review
alexisintech Dec 19, 2024
c66fd2d
update authz examples
alexisintech Dec 19, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions docs/_partials/nuxt/use-auth.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
The `useAuth()` composable provides access to the current authentication state and methods to manage the active session. You can use this composable to protect [pages](/docs/references/nuxt/protect-pages).

In the following example, the `isLoaded` property checks if Clerk has finished initializing and the `userId` property checks if the user is signed in.

```vue {{ filename: 'pages/protected-page.vue' }}
<script setup>
const { userId, isLoaded } = useAuth()
</script>

<template>
<div v-if="!isLoaded">Loading...</div>
<div v-else-if="!userId">Sign in to access this page</div>
<div v-else>Hello, {{ userId }}!</div>
</template>
```
4 changes: 2 additions & 2 deletions docs/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -2713,9 +2713,9 @@
"href": "/docs/references/nuxt/read-session-data"
},
{
"title": "Protecting pages",
"title": "Protect pages",
"wrap": false,
"href": "/docs/references/nuxt/protecting-pages"
"href": "/docs/references/nuxt/protect-pages"
}
]
]
Expand Down
31 changes: 4 additions & 27 deletions docs/quickstarts/nuxt.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ description: Add authentication and user management to your Nuxt app with Clerk.

## Configure `nuxt.config.ts`

To enable Clerk in your Nuxt app, add `@clerk/nuxt` to your modules array in `nuxt.config.ts`. This automatically configures Clerk's middleware and plugins, and imports Clerk's components.
To enable Clerk in your Nuxt app, add `@clerk/nuxt` to your modules array in `nuxt.config.ts`. This automatically configures Clerk's middleware and plugins and imports Clerk's components.

```ts {{ filename: 'nuxt.config.ts', mark: [2] }}
export default defineNuxtConfig({
Expand All @@ -84,7 +84,7 @@ description: Add authentication and user management to your Nuxt app with Clerk.

## Create a header with Clerk components

[Nuxt 3](https://nuxt.com/docs/migration/auto-imports) automatically imports and makes available all components in the `components/` directory globally, without requiring explicit imports. See the [Nuxt docs](https://nuxt.com/docs/guide/concepts/auto-imports) for details.
Nuxt 3 automatically imports and makes all components in the `components/` directory globally available without requiring explicit imports. See the [Nuxt docs](https://nuxt.com/docs/guide/concepts/auto-imports) for details.

You can control which content signed-in and signed-out users can see with Clerk's [prebuilt control components](/docs/components/overview#what-are-control-components).

Expand All @@ -93,7 +93,7 @@ description: Add authentication and user management to your Nuxt app with Clerk.
- [`<SignedIn>`](/docs/components/control/signed-in): Children of this component can only be seen while **signed in**.
- [`<SignedOut>`](/docs/components/control/signed-out): Children of this component can only be seen while **signed out**.
- [`<UserButton />`](/docs/components/user/user-button): Shows the signed-in user's avatar. Selecting it opens a dropdown menu with account management options.
- [`<SignInButton />`](/docs/components/unstyled/sign-in-button): An unstyled component that links to the sign-in page or displays the sign-in modal.
- [`<SignInButton />`](/docs/components/unstyled/sign-in-button): An unstyled component that links to the sign-in page or displays the sign-in modal. In this example, since no props or [environment variables](/docs/deployments/clerk-environment-variables) are set for the sign-in URL, this component links to the [Account Portal sign-in page](/docs/customization/account-portal/overview#sign-in).

```vue {{ filename: 'app.vue', mark: [2, [6, 13]] }}
<script setup lang="ts">
Expand All @@ -116,29 +116,6 @@ description: Add authentication and user management to your Nuxt app with Clerk.
</template>
```

## Protect your API routes

API routes in Nuxt 3 are handled by [`eventHandler`](https://nuxt.com/docs/guide/directory-structure/server) functions in the `server/api` directory. Files in this directory automatically become API endpoints matching their path (e.g., `server/api/user.ts` becomes `/api/user`).

To protect your API routes, use the `event.context.auth` object in your event handlers. This object is automatically injected by Clerk and contains authentication information about the current request.

The following example protects an API route by checking if a user is authenticated. If the user isn't authenticated, the route returns a 401 Unauthorized error.

```ts {{ filename: 'server/api/auth/index.ts' }}
export default defineEventHandler((event) => {
const { userId } = event.context.auth

if (!userId) {
throw createError({
statusCode: 401,
statusMessage: 'Unauthorized',
})
}

return { userId }
})
```

## Create your first user

Run your project with the following command:
Expand All @@ -165,7 +142,7 @@ description: Add authentication and user management to your Nuxt app with Clerk.
Learn more about Clerk components, how to customize them, and how to use Clerk's client-side helpers using the following guides.

<Cards>
- [Protect API routes using Clerk Middleware](/docs/references/nuxt/clerk-middleware)
- [Protect API routes using `clerkMiddleware()`](/docs/references/nuxt/clerk-middleware)
- Learn how to protect specific API routes from unauthenticated users.

---
Expand Down
2 changes: 1 addition & 1 deletion docs/references/backend/overview.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ To access a resource, you must first instantiate a `clerkClient` instance.

If you would like to customize the behavior of the JavaScript Backend SDK, you can instantiate a `clerkClient` instance yourself by calling `createClerkClient()` and passing in [`options`](#create-clerk-client-options).

<Tabs type="framework" items={["Next.js", "Remix", "Fastify", "Astro", "Tanstack Start", "Express", "Nuxt"]}>
<Tabs items={["Next.js", "Remix", "Fastify", "Astro", "Tanstack Start", "Express", "Nuxt"]}>
<Tab>
```jsx
import { createClerkClient } from '@clerk/nextjs/server'
Expand Down
73 changes: 39 additions & 34 deletions docs/references/nuxt/clerk-middleware.mdx
Original file line number Diff line number Diff line change
@@ -1,19 +1,20 @@
---
title: Protecting API routes with clerkMiddleware() | Nuxt
description: Learn how to protect your Nuxt API routes using Clerk's middleware.
title: clerkMiddleware() | Nuxt
description: The clerkMiddleware() helper allows you to protect your Nuxt application using middleware.
---

The `clerkMiddleware()` helper integrates Clerk authentication into your Nuxt application through middleware to protect API routes by validating authentication server-side. You can protect API routes based on user authentication status or authorization status.
The `clerkMiddleware()` helper allows you to protect your Nuxt application **on the server-side**. It can be used to validate a user's authentication status or authorization status.

To learn how to protect pages, see the [dedicated guide](/docs/references/nuxt/protecting-pages).
> [!NOTE]
> To learn how to protect pages, see the [dedicated guide](/docs/references/nuxt/protect-pages).

## Configure `clerkMiddleware()`

By default, the Nuxt SDK **automatically** adds the `clerkMiddleware()` helper to your Nuxt application.

To **manually** configure the middleware:

1. In your `nuxt.config.ts` file, set `skipServerMiddleware: true` under the `clerk` property.
1. In your `nuxt.config.ts` file, under the `clerk` property, set `skipServerMiddleware: true`.

```ts {{ filename: 'nuxt.config.ts', mark: [[3, 5]] }}
export default defineNuxtConfig({
Expand All @@ -23,25 +24,25 @@ To **manually** configure the middleware:
},
})
```
1. In your `server/middleware/` directory, create a file named `clerk.ts`:
1. In your `server/middleware/` directory, create a file named `clerk.ts` with the following code:

```ts {{ filename: 'src/middleware/clerk.ts' }}
import { clerkMiddleware } from '@clerk/nuxt/server'
export default clerkMiddleware()
```

## Protecting API routes with `clerkMiddleware()`
## Protect API routes

You can protect routes using either or both of the following:

- [Authentication-based protection](#authentication-based-protection): Verify if the user is signed in
- [Authorization-based protection](#authorization-based-protection): Verify if the user has the required organization roles or custom permissions
- [Authentication-based protection](#authentication-based-protection): Verify if the user is signed in.
- [Authorization-based protection](#authorization-based-protection): Verify if the user has the required organization roles or custom permissions.

### Authentication-based protection

To protect routes based on user authentication status, you can check if the user is signed in by accessing the `userId` on the `auth` object.
To protect routes based on user authentication status, you can check if the user is signed in by checking the `userId` on the [`auth`](/docs/references/nuxt/overview#auth-object) object.

In the following example, the `clerkMiddleware()` helper verifies if the user is accessing an authenticated route. If the user is not signed in, an error is thrown using Nuxt's [`createError`](https://nuxt.com/docs/api/utils/create-error) utility.
In the following example, the `clerkMiddleware()` helper checks if the user is signed in and accessing a protected route. If they aren't signed in, an error is thrown using Nuxt's [`createError()`](https://nuxt.com/docs/api/utils/create-error) utility.

```tsx {{ filename: 'server/middleware/clerk.ts' }}
import { clerkMiddleware } from '@clerk/nuxt/server'
Expand All @@ -50,7 +51,6 @@ export default clerkMiddleware((event) => {
const { userId } = event.context.auth
const isAdminRoute = event.path.startsWith('/api/admin')

// Check if the user is trying to access a protected route without authentication
if (!userId && isAdminRoute) {
throw createError({
statusCode: 401,
Expand All @@ -64,53 +64,58 @@ export default clerkMiddleware((event) => {

To protect routes based on user authorization status, you can check if the user has the required organization roles or permissions. Organizations have two default roles: **Admin** (`org:admin`) and **Member** (`org:member`). You can also create custom roles and permissions. See the [dedicated guide](/docs/organizations/roles-permissions#permissions).

#### Protecting routes using default roles
#### Protecting routes using custom permissions

In the following example, the `clerkMiddleware()` helper verifies if the user is accessing an admin route. If so, it checks the `userId` and `orgRole` properties to ensure the user is both signed in and has the required admin role. If either check fails, an error is thrown using Nuxt's [`createError`](https://nuxt.com/docs/api/utils/create-error) utility.
To protect a route based on a custom permission, you can use the `has()` helper to check if a user _has_ an organization role or custom permission. It is available on the [`auth`](/docs/references/nuxt/overview#auth-object) object.

In the following example, the `clerkMiddleware()` helper checks if the user is accessing a protected route. If so, it checks if the user has the required custom permission. If they don't, an error is thrown using Nuxt's [`createError()`](https://nuxt.com/docs/api/utils/create-error) utility.

```ts {{ filename: 'server/middleware/clerk.ts' }}
import { clerkMiddleware } from '@clerk/nuxt/server'

export default clerkMiddleware((event) => {
const { userId, orgRole } = event.context.auth
const isAdminRoute = event.path.startsWith('/api/admin')
const { has } = event.context.auth
const isInvoicesRoute = event.path.startsWith('/api/invoices')
const canCreateInvoices = has({
permission: 'org:invoices:create',
})

// Check if the user is trying to access a protected route
if (isAdminRoute) {
// Check if the user is signed in and has the required admin role
if (!userId || orgRole !== 'org:admin') {
// Check if user is accessing sensitive customer data
if (isInvoicesRoute) {
// Check if user has the required permission
if (!canCreateInvoices) {
throw createError({
statusCode: 403,
statusMessage: 'Forbidden: Admin access required',
statusMessage: 'Unauthorized: Missing permission to create invoices',
})
}
}
})
```

#### Protecting routes using custom permissions
#### Protecting routes using default roles

System permissions (e.g., `org:sys_domains:manage`) aren't included in session claims and can't be used with `auth.has()` on the server-side. To perform permission checks in middleware, **you must create and use custom permissions**. See the [dedicated guide](/docs/organizations/roles-permissions#permissions).
To protect a route based on a default role, you can check the `orgRole` property on the [`auth`](/docs/references/nuxt/overview#auth-object) object.

In the following example, the `clerkMiddleware()` helper verifies if the user is accessing an invoices route. If so, it checks if the user has the required custom permission. If not, an error is thrown using Nuxt's [`createError`](https://nuxt.com/docs/api/utils/create-error) utility.
> [!WARNING]
> It's best practice to use permission-based authorization over role-based authorization, as it reduces complexity and increases security. Usually, complex role checks can be refactored with a single permission check.

In the following example, the `clerkMiddleware()` helper checks if the user is accessing a protected route. If so, it checks the `orgRole` property to ensure the user has the required admin role. If they don't, an error is thrown using Nuxt's [`createError()`](https://nuxt.com/docs/api/utils/create-error) utility.

```ts {{ filename: 'server/middleware/clerk.ts' }}
import { clerkMiddleware } from '@clerk/nuxt/server'

export default clerkMiddleware((event) => {
const { has } = event.context.auth
const isInvoicesRoute = event.path.startsWith('/api/invoices')
const canCreateInvoices = has({
permission: 'org:invoices:create',
})
const { orgRole } = event.context.auth
const isAdminRoute = event.path.startsWith('/api/admin')

// Check if user is accessing sensitive customer data
if (isInvoicesRoute) {
// Check if user has the required permission
if (!canCreateInvoices) {
// Check if the user is trying to access a protected route
if (isAdminRoute) {
// Check if the user has the required admin role
if (orgRole !== 'org:admin') {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we can also use the role property here @alexisintech? Something lik,e !has({ role: 'org:admin' })

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

throw createError({
statusCode: 403,
statusMessage: 'Forbidden: Missing invoice creation permission',
statusMessage: 'Unauthorized: Admin access required',
})
}
}
Expand Down
16 changes: 8 additions & 8 deletions docs/references/nuxt/overview.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@ The Nuxt SDK is built on top of the [Vue SDK](/docs/references/vue/overview), an
## Guides

- [Read session and user data](/docs/references/nuxt/read-session-data)
- [Protecting pages](/docs/references/nuxt/protecting-pages)
- [Protect pages](/docs/references/nuxt/protect-pages)

## Client-side helpers

The Nuxt SDK provides composables that give you access to the [`Clerk`](/docs/references/javascript/clerk/clerk) object and helper methods for authentication flows. See the [Vue SDK reference](/docs/references/vue/overview) for details.
Because the Nuxt SDK is built on top of the Clerk Vue SDK, you can use the composables that the Vue SDK provides. These composables give you access to the [`Clerk`](/docs/references/javascript/clerk/clerk) object and a set of useful helper methods for signing in and signing up. Learn more in the [Vue SDK reference](/docs/references/vue/overview).

- [`useUser()`](/docs/references/vue/use-user)
- [`useClerk()`](/docs/references/vue/use-clerk)
Expand All @@ -23,14 +23,14 @@ The Nuxt SDK provides composables that give you access to the [`Clerk`](/docs/re
- [`useSessionList()`](/docs/references/vue/use-session-list)
- [`useOrganization()`](/docs/references/vue/use-organization)

## Server-side helpers
## `Auth` object

The following references show how to integrate Clerk features into applications using Nuxt server functions and API routes.
The `Auth` object is available at `event.context.auth` in your [event handlers](https://h3.unjs.io/guide/event-handler). This JavaScript object contains important information like session data, your user's ID, as well as their organization ID. [Learn more](/docs/references/nextjs/auth-object).

### `Auth` object
## `clerkMiddleware()`

The `Auth` object is available at `event.context.auth` in your [event handlers](https://h3.unjs.io/guide/event-handler). This JavaScript object contains important information like session data, your user's ID, as well as their organization ID. Learn more about the `Auth` object [here](/docs/references/nextjs/auth-object).
The `clerkMiddleware()` helper integrates Clerk authentication and authorization into your Nuxt application through middleware. [Learn more](/docs/references/nuxt/clerk-middleware).

### `clerkMiddleware()`
## `clerkClient()`

The `clerkMiddleware()` helper integrates Clerk authentication and authorization into your Nuxt application through middleware. You can learn more [here](/docs/references/nuxt/clerk-middleware).
The `clerkClient()` helper returns an instance of the [JavaScript Backend SDK](/docs/references/backend/overview). [Learn more](/docs/references/nuxt/read-session-data#clerk-client).
54 changes: 54 additions & 0 deletions docs/references/nuxt/protect-pages.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
---
title: Protect pages in your Nuxt app with Clerk
description: Learn how to protect the pages in your Clerk + Nuxt application.
---

There are two ways to protect pages in your Nuxt application:

- [Use the `useAuth()` composable](#use-use-auth)
- [Use `defineNuxtRouteMiddleware()`](#use-define-nuxt-route-middleware)

> [!NOTE]
> To learn how to protect API routes, see the [dedicated guide](/docs/references/nuxt/clerk-middleware#protect-api-routes).

## Use `useAuth()`

<Include src="_partials/nuxt/use-auth" />
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TIL 👀


## Use `defineNuxtRouteMiddleware()`

The [`defineNuxtRouteMiddleware()`](https://nuxt.com/docs/api/utils/define-nuxt-route-middleware) utility function helps protect pages in your Nuxt application by validating authentication on the client-side. This middleware integrates seamlessly with Clerk authentication.

<Steps>
### Configure `defineNuxtRouteMiddleware()`

In your `middleware/` directory, create a file named `auth.ts` with the following code. This middleware uses the `useAuth()` composable to check if the user is signed in. If they aren't, the middleware redirects them to the sign-in page.

```ts {{ filename: 'middleware/auth.ts' }}
export default defineNuxtRouteMiddleware(() => {
const { userId } = useAuth()

// If the user is not signed in, redirect to the sign-in page
if (!userId.value) {
return navigateTo('/sign-in')
}
})
```

### Protect pages with `defineNuxtRouteMiddleware()`

To protect a page, add the middleware to the `definePageMeta()` function. In the last step, you stored the middleware in the `auth.ts` file, so you would pass `auth` in the `middleware` array.

```vue {{ filename: 'pages/dashboard.vue' }}
<script setup lang="ts">
definePageMeta({
// `auth` is the name of the middleware file
middleware: ['auth'],
})
</script>

<template>
<h1>Dashboard page</h1>
</template>
```
</Steps>
Loading
Loading