Skip to content

Migration of sample app to Nexjs SDK v4 #180

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

Open
wants to merge 10 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
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
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
[![CircleCI](https://img.shields.io/circleci/build/github/auth0-samples/auth0-nextjs-samples?style=flat-square)](https://circleci.com/gh/auth0-samples/auth0-nextjs-samples)
[![License](https://img.shields.io/:license-mit-blue.svg?style=flat)](https://opensource.org/licenses/MIT)

This is the sample code for the [Auth0 Next.js Quickstart](https://auth0.com/docs/quickstart/webapp/nextjs) using [nextjs-auth0](https://github.com/auth0/nextjs-auth0).
This is the sample code for the [Auth0 Next.js Quickstart](https://auth0.com/docs/quickstart/webapp/nextjs) using [nextjs-auth0 v4](https://github.com/auth0/nextjs-auth0).

Please check out [the sample application](./Sample-01) for an example of how to integrate the Auth0 Next.js SDK into your Next.js applications.

Expand Down
9 changes: 7 additions & 2 deletions Sample-01/.babelrc
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
{
"presets": ["next/babel"]
}
"presets": [
"@babel/preset-env",
["@babel/preset-react", { "runtime": "automatic" }],
"@babel/preset-typescript"
],
"plugins": []
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Why is this neccessary to update the SDK?

10 changes: 4 additions & 6 deletions Sample-01/.env.local.example
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
AUTH0_SECRET=replace-with-your-own-secret-generated-with-openssl
AUTH0_BASE_URL=http://localhost:3000
AUTH0_ISSUER_BASE_URL='https://{DOMAIN}'
AUTH0_CLIENT_ID='{CLIENT_ID}'
AUTH0_CLIENT_SECRET='{CLIENT_SECRET}'
AUTH0_AUDIENCE=
AUTH0_SCOPE='openid profile'
APP_BASE_URL=http://localhost:3000
AUTH0_DOMAIN={DOMAIN}
AUTH0_CLIENT_ID={CLIENT_ID}
AUTH0_CLIENT_SECRET={CLIENT_SECRET}
330 changes: 311 additions & 19 deletions Sample-01/README.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
# Auth0 Next.js SDK Sample Application

This sample demonstrates the integration of [Auth0 Next.js SDK](https://github.com/auth0/nextjs-auth0) into a Next.js application created using [create-next-app](https://nextjs.org/docs/api-reference/create-next-app). The sample is a companion to the [Auth0 Next.js SDK Quickstart](https://auth0.com/docs/quickstart/webapp/nextjs).
This sample demonstrates the integration of [Auth0 Next.js SDK v4](https://github.com/auth0/nextjs-auth0) into a Next.js application created using [create-next-app](https://nextjs.org/docs/api-reference/create-next-app). The sample is a companion to the [Auth0 Next.js SDK Quickstart](https://auth0.com/docs/quickstart/webapp/nextjs).

This sample demonstrates the following use cases:

- [Login](https://github.com/auth0-samples/auth0-nextjs-samples/blob/main/Sample-01/components/NavBar.jsx#L61-L67)
- [Logout](https://github.com/auth0-samples/auth0-nextjs-samples/blob/main/Sample-01/components/NavBar.jsx#L93-L95)
- [Showing the user profile](https://github.com/auth0-samples/auth0-nextjs-samples/blob/main/Sample-01/pages/profile.jsx)
- [Protecting client-side rendered pages](https://github.com/auth0-samples/auth0-nextjs-samples/blob/main/Sample-01/pages/profile.jsx#L43-L46)
- [Calling APIs](https://github.com/auth0-samples/auth0-nextjs-samples/blob/main/Sample-01/pages/external.jsx)
- Login
- Logout
- Showing the user profile
- Protecting routes using middleware
- Calling APIs with access tokens

## Project setup

Expand All @@ -22,37 +22,329 @@ npm install

### Create an API

For the **External API** page to work, you will need to [create an API](https://auth0.com/docs/authorization/apis) using the [management dashboard](https://manage.auth0.com/#/apis). This will give you an API Identifier that you can use in the `AUTH0_AUDIENCE` environment variable below. Then you will need to [add a permission](https://auth0.com/docs/get-started/dashboard/add-api-permissions) named `read:shows` to your API. To get your app to ask for that permission, include it in the value of the `AUTH0_SCOPE` environment variable.
For the **External API** page to work, you will need to [create an API](https://auth0.com/docs/authorization/apis) using the [management dashboard](https://manage.auth0.com/#/apis). This will give you an API Identifier that you can use in the `AUTH0_AUDIENCE` environment variable below. Then you will need to [add a permission](https://auth0.com/docs/get-started/dashboard/add-api-permissions) named `read:shows` to your API.

If you do not wish to use an API or observe the API call working, you should not specify the `AUTH0_AUDIENCE` and `AUTH0_SCOPE` values in the next steps.
If you do not wish to use an API or observe the API call working, you should not specify the `AUTH0_AUDIENCE` value in the next steps.
Copy link
Contributor

Choose a reason for hiding this comment

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

AUTH0_AUDIENCE?


### Configure credentials

The project needs to be configured with your Auth0 Domain, Client ID and Client Secret for the authentication flow to work.

To do this, first copy `.env.local.example` into a new file in the same folder called `.env.local`, and replace the values with your own Auth0 application credentials (see more info about [loading environmental variables in Next.js](https://nextjs.org/docs/basic-features/environment-variables)):
To do this, first copy `.env.local.example` into a new file in the same folder called `.env.local`, and replace the values with your own Auth0 application credentials:
Copy link
Contributor

Choose a reason for hiding this comment

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

Why is this link (https://nextjs.org/docs/basic-features/environment-variables) no longer relevant?


```sh
# A long secret value used to encrypt the session cookie
AUTH0_SECRET='LONG_RANDOM_VALUE'
# The base url of your application
AUTH0_BASE_URL='http://localhost:3000'
# The url of your Auth0 tenant domain
AUTH0_ISSUER_BASE_URL='https://YOUR_AUTH0_DOMAIN.auth0.com'
# Your Auth0 application's Client ID
AUTH0_CLIENT_ID='YOUR_AUTH0_CLIENT_ID'
# Your Auth0 application's Client Secret
AUTH0_CLIENT_SECRET='YOUR_AUTH0_CLIENT_SECRET'
# Your Auth0 API's Identifier
# OMIT if you do not want to use the API part of the sample
AUTH0_AUDIENCE='YOUR_AUTH0_API_IDENTIFIER'
# The permissions your app is asking for
# OMIT if you do not want to use the API part of the sample
AUTH0_SCOPE='openid profile email read:shows'
# Your Auth0 tenant domain
AUTH0_DOMAIN='YOUR_AUTH0_DOMAIN.auth0.com'
# The base url of your application
APP_BASE_URL='http://localhost:3000'
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we keep the order, so we simplify the diff?

Copy link
Contributor

Choose a reason for hiding this comment

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

Order isnt maintained

```

**Note**: Make sure you replace `AUTH0_SECRET` with your own secret (you can generate a suitable string using `openssl rand -hex 32` on the command line).

## Step-by-Step Implementation Guide

This guide will walk you through integrating Auth0 with Next.js using the Auth0 Next.js SDK v4.

### Step 1: Create a Next.js App

If you don't have an existing Next.js application, create one using:

```bash
npx create-next-app@latest my-auth0-app
cd my-auth0-app
```

### Step 2: Install the Auth0 SDK

Install the Auth0 Next.js SDK v4:

```bash
npm install @auth0/nextjs-auth0@4.2.0
```

### Step 3: Set Up Auth0 Configuration

1. **Set up your Auth0 account**:
- Sign up for an Auth0 account at [https://auth0.com](https://auth0.com) if you don't have one
- Create a new application in the Auth0 Dashboard
- Choose "Regular Web Application" as the application type

2. **Configure Auth0 application settings**:
- Set the "Allowed Callback URLs" to `http://localhost:3000/auth/callback`
- Set the "Allowed Logout URLs" to `http://localhost:3000`
- Set the "Allowed Web Origins" to `http://localhost:3000`

3. **Create the environment variables file**:
- Create a `.env.local` file in your project root with the following variables:


```sh
# A long secret value used to encrypt the session cookie
AUTH0_SECRET='LONG_RANDOM_VALUE'
# The base url of your application
APP_BASE_URL='http://localhost:3000'
# Your Auth0 application's Client ID
AUTH0_CLIENT_ID='YOUR_AUTH0_CLIENT_ID'
# Your Auth0 application's Client Secret
AUTH0_CLIENT_SECRET='YOUR_AUTH0_CLIENT_SECRET'
```

### Step 4: Initialize the Auth0 Client

Create a file at `lib/auth0.ts` with the following content:

```typescript
import { Auth0Client } from "@auth0/nextjs-auth0/server";

export const auth0 = new Auth0Client({
// Options are loaded from environment variables by default
authorizationParameters: {
scope: "openid profile email",
}
});
```

If you need to call an API, adjust the scope to include the required permissions:

```typescript
authorizationParameters: {
scope: "openid profile email read:shows",
}
```

### Step 5: Set Up Middleware for Route Protection

Create a file named `middleware.ts` in your project root:

```typescript
import type { NextRequest } from "next/server";
import { auth0 } from "./lib/auth0";

export async function middleware(request: NextRequest) {
return await auth0.middleware(request);
}

export const config = {
matcher: [
"/((?!_next/static|_next/image|favicon.ico|sitemap.xml|robots.txt).*)",
],
};
```

This middleware will handle authentication for all routes except static assets.

### Step 6: Create a Profile Page

Create a profile page to display user information at `app/profile/page.tsx`:

```typescript
import { auth0 } from "../../lib/auth0";
import { redirect } from "next/navigation";

export default async function ProfilePage() {
const session = await auth0.getSession();

// Redirect to login if not authenticated
if (!session?.user) {
return redirect("/auth/login");
}

return (
<div>
<h1>Profile</h1>
<h2>{session.user.name}</h2>
<p>{session.user.email}</p>
<img src={session.user.picture} alt="Profile" width="100" />

<pre>{JSON.stringify(session.user, null, 2)}</pre>
</div>
);
}
```

### Step 7: Create Navigation Component

Create a navigation component with login/logout buttons at `components/NavBar.tsx`:

```typescript
import Link from "next/link";
import { auth0 } from "../lib/auth0";

export default async function NavBar() {
const session = await auth0.getSession();
const isAuthenticated = !!session?.user;

return (
<nav>
<ul style={{ display: "flex", gap: "1rem", listStyle: "none" }}>
<li>
<Link href="/">Home</Link>
</li>
{isAuthenticated && (
<li>
<Link href="/profile">Profile</Link>
</li>
)}
<li>
{isAuthenticated ? (
<a href="/auth/logout">Logout</a>
) : (
<a href="/auth/login">Login</a>
)}
</li>
</ul>
</nav>
);
}
```

### Step 8: Integrate API Access (Optional)

If you want to access an external API with the user's access token, create an API route:

```typescript
// app/api/shows/route.js
import { auth0 } from '../../../lib/auth0';
import { NextResponse } from 'next/server';

export async function GET(req) {
// Check if user is authenticated
const session = await auth0.getSession();
if (!session) {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
}

try {
// Get access token
const { accessToken } = await auth0.getAccessToken();

const apiPort = process.env.API_PORT || 3001;
const response = await fetch(`http://localhost:${apiPort}/api/shows`, {
headers: {
Authorization: `Bearer ${accessToken}`
}
});
const shows = await response.json();

return NextResponse.json(shows);
} catch (error) {
console.error('Auth0 or API error:', error);
return NextResponse.json({ error: error.message }, { status: error.status || 500 });
}
}
```

### Step 9: Update Root Layout

Add the NavBar to your root layout at `app/layout.tsx`:

```typescript
import { Inter } from 'next/font/google';
import NavBar from '../components/NavBar';

const inter = Inter({ subsets: ['latin'] });

export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="en">
<body className={inter.className}>
<NavBar />
<main>{children}</main>
</body>
</html>
);
}
```

### Step 11: Start your Application

Start your Next.js application:

```bash
npm run dev
```

Visit http://localhost:3000 and test the authentication flow.

## Key Changes in v4

This sample has been updated to use Auth0 NextJS SDK v4, which includes several important changes:

1. **New Auth0Client Class**: We now use the `Auth0Client` from `@auth0/nextjs-auth0/server` which provides a simpler API.

2. **Middleware-based Protection**: Route protection now uses Next.js middleware instead of higher-order components or hooks for server-side protection.

3. **App Router Support**: The sample now works with Next.js App Router, with API routes implemented as route handlers.

5. **Environment Variables**: The configuration has been simplified with the required environment variables loaded automatically.

## Implementation Details

### Auth0 Client Initialization

```typescript
// lib/auth0.ts
import { Auth0Client } from "@auth0/nextjs-auth0/server";

export const auth0 = new Auth0Client({
// Options are loaded from environment variables by default
authorizationParameters: {
scope: "openid profile email offline_access read:shows",
}
});
```

### Middleware for Route Protection

```typescript
// middleware.ts
import type { NextRequest } from "next/server"
import { auth0 } from "./lib/auth0"

export async function middleware(request: NextRequest) {
return await auth0.middleware(request)
}

export const config = {
matcher: [
"/((?!_next/static|_next/image|favicon.ico|sitemap.xml|robots.txt).*)",
],
}
```

### API Route Implementation

```javascript
// app/api/shows/route.js
import { auth0 } from '../../../lib/auth0';
import { NextResponse } from 'next/server';

export async function GET(req) {
const session = await auth0.getSession();
if (!session) {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
}

try {
const { accessToken } = await auth0.getAccessToken();
// Use the access token to call your API
// ...
} catch (error) {
// Error handling
}
}
```

## Run the sample

### Compile and hot-reload for development
Expand Down
Loading