Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
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
95 changes: 30 additions & 65 deletions plugins/auth0/skills/auth0-fastify/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
name: auth0-fastify
description: Use when adding authentication (login, logout, protected routes) to Fastify web applications - integrates @auth0/auth0-fastify for session-based auth. For stateless Fastify APIs use auth0-fastify-api instead.
description: "Use when adding authentication to Fastify web applications β€” integrates @auth0/auth0-fastify for session-based login, logout, OAuth callback handling, user profile retrieval, and access token management. Registers /auth/login, /auth/logout, and /auth/callback routes automatically. For stateless Fastify APIs receiving JWT Bearer tokens, use auth0-fastify-api instead."

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Why do we need to include the routes it registered in the skills description?

receiving JWT Bearer tokens,

This is not correct, Fastify API handles more than just Bearer tokens.

license: Apache-2.0
metadata:
author: Auth0 <support@auth0.com>
Expand All @@ -12,26 +12,12 @@ metadata:

# Auth0 Fastify Integration

Add authentication to Fastify web applications using @auth0/auth0-fastify.
Add session-based authentication to Fastify web applications using @auth0/auth0-fastify.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

session-based sounds confusing when the SDK supports stateless and statefull configurations, where in stateful everything stays in the cookie.


---

## Prerequisites

- Fastify application (v5.x or newer)
- Node.js 20 LTS or newer
- Auth0 account and application configured
- If you don't have Auth0 set up yet, use the `auth0-quickstart` skill first

## When NOT to Use

- **Single Page Applications** - Use `auth0-react`, `auth0-vue`, or `auth0-angular` for client-side auth
- **Next.js applications** - Use `auth0-nextjs` skill which handles both client and server
- **Mobile applications** - Use `auth0-react-native` for React Native/Expo
- **Stateless APIs** - Use `@auth0/auth0-fastify-api` instead for JWT validation without sessions
- **Microservices** - Use JWT validation for service-to-service auth

---
> **Agent instruction:** Before providing SDK setup instructions, fetch the latest release version by running:
> ```
> gh api repos/auth0/auth0-fastify/releases/latest --jq '.tag_name'
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated
> ```

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

What is the intention with removing prerequisites and when NOT to use here?

Comment on lines +17 to +20

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟑 Minor | ⚑ Quick win

Add blank line before the fenced code block.

Markdown specification requires blank lines around fenced code blocks. Add a blank line between line 17 and line 18 to resolve the MD031 linting warning.

πŸ“ Proposed fix
 > **Agent instruction:** Before providing SDK setup instructions, fetch the latest release version by running:
+>
 > ```bash
 > gh api repos/auth0/auth0-fastify/releases/latest --jq '.tag_name'
 > ```

As per coding guidelines, static analysis flagged: MD031 blanks-around-fences.

πŸ“ Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
> **Agent instruction:** Before providing SDK setup instructions, fetch the latest release version by running:
> ```bash
> gh api repos/auth0/auth0-fastify/releases/latest --jq '.tag_name'
> ```
> **Agent instruction:** Before providing SDK setup instructions, fetch the latest release version by running:
>
>
🧰 Tools
πŸͺ› markdownlint-cli2 (0.22.1)

[warning] 18-18: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)

πŸ€– Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@plugins/auth0/skills/auth0-fastify/SKILL.md` around lines 17 - 20, Add a
blank line before the fenced code block in the "Agent instruction" section so
the Markdown has an empty line between the preceding text ("Before providing SDK
setup instructions, fetch the latest release version by running:") and the
opening triple backticks; locate the fenced block in SKILL.md (the "gh api
repos/auth0/auth0-fastify/releases/latest --jq '.tag_name'" snippet) and insert
one empty line above the ``` to satisfy MD031.


## Quick Start Workflow

Expand All @@ -43,7 +29,9 @@ npm install @auth0/auth0-fastify fastify @fastify/view ejs dotenv

### 2. Configure Environment

Create `.env`:
**For automated setup with Auth0 CLI**, see [Setup Guide](references/setup.md).

**For manual setup**, create `.env`:

```bash
AUTH0_DOMAIN=your-tenant.auth0.com
Expand All @@ -55,6 +43,8 @@ APP_BASE_URL=http://localhost:3000

Generate secret: `openssl rand -hex 64`

**Verify before proceeding:** In the Auth0 Dashboard, confirm the application is set to **Regular Web Application** (not SPA) and that `http://localhost:3000/auth/callback` is listed in Allowed Callback URLs, `http://localhost:3000` in Allowed Logout URLs and Allowed Web Origins.

### 3. Configure Auth Plugin

Create your Fastify server (`server.js`):
Expand All @@ -68,13 +58,11 @@ import ejs from 'ejs';

const fastify = Fastify({ logger: true });

// Register view engine
await fastify.register(fastifyView, {
engine: { ejs },
root: './views',
});

// Configure Auth0 plugin
await fastify.register(fastifyAuth0, {
domain: process.env.AUTH0_DOMAIN,
clientId: process.env.AUTH0_CLIENT_ID,
Expand All @@ -86,10 +74,10 @@ await fastify.register(fastifyAuth0, {
fastify.listen({ port: 3000 });
```

This automatically creates:
- `/auth/login` - Login endpoint
- `/auth/logout` - Logout endpoint
- `/auth/callback` - OAuth callback
This automatically registers:
- `/auth/login` β€” Redirects to Auth0 Universal Login
- `/auth/logout` β€” Clears session and redirects to Auth0 logout
- `/auth/callback` β€” Handles OAuth callback and creates session

### 4. Add Routes

Expand Down Expand Up @@ -118,59 +106,36 @@ fastify.get('/profile', {

### 5. Test Authentication

Start your server:

```bash
node server.js
```

Visit `http://localhost:3000` and test the login flow.
Visit `http://localhost:3000` and verify:
1. Clicking login redirects to Auth0 Universal Login
2. After login, you are redirected back with a valid session
3. `/profile` shows user info when authenticated
4. Logout clears the session and redirects home

If login redirects fail, check the server logs for callback URL mismatch errors β€” the most common cause is a missing or incorrect Allowed Callback URL in the Auth0 Dashboard.

---

## Common Mistakes

| Mistake | Fix |
|---------|-----|
| Forgot to add callback URL in Auth0 Dashboard | Add `/auth/callback` path to Allowed Callback URLs (e.g., `http://localhost:3000/auth/callback`) |
| Missing or weak SESSION_SECRET | Generate secure 64-char secret with `openssl rand -hex 64` and store in .env |
| App created as SPA type in Auth0 | Must be Regular Web Application type for server-side auth |
| Session secret exposed in code | Always use environment variables, never hardcode secrets |
| Wrong appBaseUrl for production | Update APP_BASE_URL to match your production domain |
| Not awaiting fastify.register | Fastify v4+ requires awaiting plugin registration |
| Callback URL mismatch | Add `http://localhost:3000/auth/callback` to Allowed Callback URLs in Auth0 Dashboard |

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Why did we remove common mistakes?

| App created as SPA type | Must be **Regular Web Application** for server-side session auth |
| Weak SESSION_SECRET | Generate with `openssl rand -hex 64` β€” minimum 64 characters |
| Not awaiting `fastify.register` | Fastify v4+ requires `await` on plugin registration |

---

## Related Skills

- `auth0-quickstart` - Basic Auth0 setup
- `auth0-migration` - Migrate from another auth provider
- `auth0-mfa` - Add Multi-Factor Authentication
- `auth0-cli` - Manage Auth0 resources from the terminal

---
## Detailed Documentation

## Quick Reference

**Plugin Options:**
- `domain` - Auth0 tenant domain (required)
- `clientId` - Auth0 client ID (required)
- `clientSecret` - Auth0 client secret (required)
- `appBaseUrl` - Application URL (required)
- `sessionSecret` - Session encryption secret (required, min 64 chars)
- `audience` - API audience (optional, for calling APIs)

**Client Methods:**
- `fastify.auth0Client.getSession({ request, reply })` - Get user session
- `fastify.auth0Client.getUser({ request, reply })` - Get user profile
- `fastify.auth0Client.getAccessToken({ request, reply })` - Get access token
- `fastify.auth0Client.logout(options, { request, reply })` - Logout user

**Common Use Cases:**
- Protected routes β†’ Use `preHandler` to check session (see Step 4)
- Check auth status β†’ `!!session`
- Get user info β†’ `getUser({ request, reply })`
- Call APIs β†’ `getAccessToken({ request, reply })`
- **[Setup Guide](references/setup.md)** β€” Automated setup with Auth0 CLI, environment configuration
- **[Integration Guide](references/integration.md)** β€” Protected routes with preHandlers, calling APIs with access tokens, error handling
- **[API Reference](references/api.md)** β€” Plugin options, client methods, session management

---

Expand Down
24 changes: 24 additions & 0 deletions plugins/auth0/skills/auth0-fastify/references/api.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# API Reference

## Plugin Options

| Option | Required | Description |
|--------|----------|-------------|
| `domain` | Yes | Auth0 tenant domain |
| `clientId` | Yes | Auth0 application Client ID |
| `clientSecret` | Yes | Auth0 application Client Secret |
| `appBaseUrl` | Yes | Application URL (e.g. `http://localhost:3000`) |
| `sessionSecret` | Yes | Session encryption secret (min 64 chars) |
| `audience` | No | API audience identifier β€” required when calling protected APIs |
| `routes` | No | Customize auth route paths (default: `/auth/login`, `/auth/logout`, `/auth/callback`) |

## Client Methods

All methods are available on `fastify.auth0Client` after plugin registration.

| Method | Returns | Description |
|--------|---------|-------------|
| `getSession({ request, reply })` | `Session \| null` | Returns the current user session, or `null` if not authenticated |

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

There is no Session type.

| `getUser({ request, reply })` | `UserProfile` | Returns the authenticated user's profile (name, email, picture) |

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

There is no UserProfile type.

| `getAccessToken({ request, reply })` | `{ token }` | Returns an access token for calling protected APIs |
| `logout(options, { request, reply })` | `void` | Clears the session and redirects to Auth0 logout |
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated
64 changes: 64 additions & 0 deletions plugins/auth0/skills/auth0-fastify/references/integration.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# Integration Guide

## Protected Routes

Use a `preHandler` hook to require authentication on any route:

```javascript
fastify.get('/dashboard', {
preHandler: async (request, reply) => {
const session = await fastify.auth0Client.getSession({ request, reply });
if (!session) {
return reply.redirect('/auth/login');
}
}
}, async (request, reply) => {
const user = await fastify.auth0Client.getUser({ request, reply });
return reply.view('views/dashboard.ejs', { user });
});
```
Comment thread
coderabbitai[bot] marked this conversation as resolved.

## Calling a Protected API

To call an external API protected by Auth0, configure an `audience` and retrieve the access token:

```javascript
// In plugin registration, add audience:
await fastify.register(fastifyAuth0, {
domain: process.env.AUTH0_DOMAIN,
clientId: process.env.AUTH0_CLIENT_ID,
clientSecret: process.env.AUTH0_CLIENT_SECRET,
appBaseUrl: process.env.APP_BASE_URL,
sessionSecret: process.env.SESSION_SECRET,
audience: process.env.AUTH0_AUDIENCE,
});

// In a route handler:
fastify.get('/api-data', {
preHandler: async (request, reply) => {
const session = await fastify.auth0Client.getSession({ request, reply });
if (!session) return reply.redirect('/auth/login');
}
}, async (request, reply) => {
const { token } = await fastify.auth0Client.getAccessToken({ request, reply });
const response = await fetch('https://api.example.com/data', {
headers: { Authorization: `Bearer ${token}` },
});
const data = await response.json();
return reply.view('views/data.ejs', { data });
});
```
Comment thread
coderabbitai[bot] marked this conversation as resolved.

## Error Handling

Handle authentication errors by checking the session state and server logs:

```javascript
fastify.setErrorHandler(async (error, request, reply) => {
if (error.statusCode === 401) {
return reply.redirect('/auth/login');
}
fastify.log.error(error);
return reply.status(500).send({ error: 'Internal Server Error' });
});
```
43 changes: 43 additions & 0 deletions plugins/auth0/skills/auth0-fastify/references/setup.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# Setup Guide

## Automated Setup with Auth0 CLI

```bash
# 1. Authenticate
auth0 login

# 2. Create a Regular Web Application
auth0 apps create \
--name "My Fastify App" \
--type regular \
--callbacks "http://localhost:3000/auth/callback" \
--logout-urls "http://localhost:3000" \
--origins "http://localhost:3000" \
--reveal-secrets

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Why are we, by default, exposing the secret to the agent as opposed to how we do it in other skills?


# 3. Copy the Domain, Client ID, and Client Secret from the output into .env
```

## Environment Variables

| Variable | Description |
|----------|-------------|
| `AUTH0_DOMAIN` | Auth0 tenant domain (e.g. `dev-abc123.us.auth0.com`) β€” no `https://` prefix |
| `AUTH0_CLIENT_ID` | Application Client ID from Auth0 Dashboard |
| `AUTH0_CLIENT_SECRET` | Application Client Secret β€” never commit to source control |
| `SESSION_SECRET` | Encryption key for session cookies β€” generate with `openssl rand -hex 64` |
| `APP_BASE_URL` | Full application URL including protocol and port (e.g. `http://localhost:3000`) |

## Production Configuration

Update `.env` for production:

```bash
AUTH0_DOMAIN=your-tenant.auth0.com
AUTH0_CLIENT_ID=your-production-client-id
AUTH0_CLIENT_SECRET=your-production-client-secret
SESSION_SECRET=<new-production-secret>
APP_BASE_URL=https://your-production-domain.com
```

Update the Auth0 Dashboard to include your production callback URL (`https://your-production-domain.com/auth/callback`) in Allowed Callback URLs and your production domain in Allowed Logout URLs and Allowed Web Origins.