- Authors
- Name
- Nguyễn Đức Xinh
- Published on
- Published on
Hướng dẫn tích hợp Auth0 vào ứng dụng NextJS để xác thực người dùng(Authentication)
Bảo mật ứng dụng của bạn là rất quan trọng. Sử dụng Auth0 giúp việc triển khai xác thực trở nên đơn giản với các giải pháp mạnh mẽ, linh hoạt và có thể tùy chỉnh. Hướng dẫn này sẽ giúp bạn thiết lập xác thực trong ứng dụng Next.js bằng Auth0.
Auth0 Là Gì?
Auth0 là một nền tảng xác thực và phân quyền, cung cấp quyền truy cập an toàn cho các ứng dụng và API. Nó hỗ trợ nhiều phương thức xác thực, bao gồm đăng nhập bằng mạng xã hội, single sign-on (SSO), và xác thực không dùng mật khẩu, làm cho Auth0 trở thành lựa chọn phổ biến cho các ứng dụng web hiện đại.
Đăng ký tài khoản Auth0
Bước đầu tiên là cần có 1 tài khoản Auth0. Nếu bạn đã có rồi thì có thể bỏ qua bước này.
- Truy cập https://auth0.auth0.com/
- Nhấn
Sign up
-> https://auth0.com/signup Ở đây bạn có thể đăng ký bằng email hoặc thông qua SNS như: Google, Github, Microsoft.
Sau khi đăng ký xong thì bạn sẽ vào được màn hình Dashboard. Với role owner Admin thì sẽ hiển thị như sau:
Tạo Application mới.
-
Truy cập https://manage.auth0.com/dashboard
-
Chuyển đến Applications -> Applications -> Create Application và nhập thông tin như sau:
-
Name: Next Auth0
-
Choose an application type: Single Page Web Applications
Sau khi tạo xong App, Mở sang tab Settings lưu lại các thông tin sau dùng để cấu hình trong app NextJS.
- Domain
- Client ID
- Client Secret
Cấu hình Auth0
Cấu hình Application URIs
Ở tab Settings, mục Application URIs bạn cần thêm URL của app của bạn. Ở demo này mình chạy Local NextJS nên sẽ có url là http://localhost:3000
- Application Login URL: Để trống và nhập sau. Vì Auth0 yêu cầu https
- Allowed Callback URLs: http://localhost:3000/auth/callback
- Allowed Logout URLs: http://localhost:3000/auth/logout
- Allowed Web Origins: http://localhost:3000
Nếu không đặt đúng giá trị, bạn sẽ gặp lỗi như sau:
Các phần còn lại bạn để mặc định.
Cross-Origin Authentication
Cấu hình Token Expiration
Cấu hình Refresh Token Rotation
Tạo example Next app
Đối với React, Mình recommend sử dụng Framework khi bắt đầu React app. Ở đây mình chọn NextJS. Bạn có thể xem chi tiết tại đây: https://react.dev/learn/start-a-new-react-project
Để cài đặt next bạn chạy lệnh sau và trả lời 1 số prompt:
npx create-next-app@latest example-nextjs
Truy cập next app và chạy ứng dụng bằng lệnh sau:
cd example-nextjs
npm run dev
Mở trình duyệt và nhập đường dẫn http://localhost:3000/ để xem kết quả NextJS
Cài đặt Auth0 Next.js SDK
Chạy lệnh sau trong thư mục dự án của bạn để cài đặt SDK Auth0 Next.js:
npm install @auth0/nextjs-auth0
# Đối với Next 15 bạn sử dụng v4 beta
npm i @auth0/nextjs-auth0@4.0.0-beta.0
Auth0 Next.js SDK Cùng cấp 1 số method để có thể tích hợp Auth0 vào Nextjs.
- Backend: Route handler
- Frontend: React Context và React hooks
Cấu hình Auth0 Next.js SDK
Trước tiên bạn cần generate giá trị Secret bằng lệnh sau:
openssl rand -hex 32
# 5ba273ccf86990cec4e8a30f09859834c19aea094afc9f6bc0a5357fffbfabfa
Trong thư mục gốc của dự án, hãy thêm tệp .env.local
với các biến môi trường sau:
AUTH0_SECRET='5ba273ccf86990cec4e8a30f09859834c19aea094afc9f6bc0a5357fffbfabfa'
APP_BASE_URL='http://localhost:3000'
AUTH0_CLIENT_ID='qBqi4MnLOOCsaaCkQOyCUHtqRWdqMxQH'
AUTH0_CLIENT_SECRET='QD-EI88JAB0SkwBXL-1yyGs86g4w6yXBYfZ4lLRoAYkhbwYPKSIJbL5fI3O862l6'
AUTH0_DOMAIN='dev-bvgptako.auth0.com'
- AUTH0_SECRET: Giá trị Secret được sử dụng để mã hóa session cookie. Bạn có thể tạo chuỗi phù hợp bằng cách sử dụng
openssl rand -hex 32
trên CLI như hướng dẫn ở trên. - APP_BASE_URL: URL của ứng dụng bạn đang chạy.
- AUTH0_DOMAIN: URL của Auth0 tenant domain. Bạn lấy giá trị ở trong Auth0 Application -> Basic Information -> Domain. Nếu bạn sử dụng custom domain với Auth0, đặt giá trị này thành custom domain của bạn.
- AUTH0_CLIENT_ID: Client ID của ứng dụng Auth0 của bạn. Bạn có thể lấy từ Auth0 Application -> Basic Information -> Slient Id.
- AUTH0_CLIENT_SECRET: Client Secret. của ứng dụng Auth0 của bạn. Bạn có thể lấy từ Auth0 Application -> Basic Information -> Slient Secret.
Tạo Auth0 SDK client
Chúng ta sẽ tạo instance của Auth0 client. Instance này sẽ được import và sử dụng ở mọi nơi mà bạn cần truy cập các method authentication methods ở phía server.
Thêm nội dung vào file lib/auth0.ts
như sau:
import { Auth0Client } from "@auth0/nextjs-auth0/server"
export const auth0 = new Auth0Client()
Thêm authentication middleware
Tạo file middleware.ts
vào thư mục root của dự án.
Nếu bạn sử dụng src
, đường dẫn middleware.ts
sẽ là src/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: [
/*
* Match all request paths except for the ones starting with:
* - _next/static (static files)
* - _next/image (image optimization files)
* - favicon.ico, sitemap.xml, robots.txt (metadata files)
*/
"/((?!_next/static|_next/image|favicon.ico|sitemap.xml|robots.txt).*)",
],
}
Lưu ý: ở SDK V4 sẽ không còn support dynamic API route handler: UserProvider
, handleAuth
Sử dụng Auth0
Cập nhật trang Home
bằng cách thay đổi nội dung tệp src/app/page.tsx
như sau:
import { auth0 } from "@/lib/auth0"
export default async function Home() {
const session = await auth0.getSession()
if (!session) {
return (
<main className="flex gap-2 p-5">
<a className="rounded-full border border-solid border-black/[.08] flex items-center justify-center text-sm h-10 px-4" href="/auth/login?screen_hint=signup">Sign up</a>
<a className="rounded-full border border-solid border-black/[.08] flex items-center justify-center text-sm h-10 px-4" href="/auth/login">Log in</a>
</main>
)
}
return (
<main>
<h1>Welcome, {session.user.name}!</h1>
</main>
)
}
Lưu ý các link Log in, Sign up cần dùng thẻ <a>
thay vì Link
để đảm bảo routing không thực hiện bởi client-side. Vì điều đó có thể dẫn đến 1 số behavior không mong muốn.
Tiếp theo, mở trình duyệt tại đường dẫn: http://localhost:3000 để đến kiểm tra.
Khi người dùng click vào button Log in, sẽ chuyển hướng người dùng đến trang Auth0 Universal Login, Tại đây Auth0 có thể xác thực người dùng. Sau khi xác thực thành công, Auth0 sẽ chuyển hướng người dùng trở lại ứng dụng của bạn.
Ví dụ ở đây mình sẽ login bằng google.
Sau khi xác thực thành công sẽ chuyển hướng người dùng trở lại ứng dụng của bạn và tại đây ta có thể hiển thị thông tin người dùng.
Truy cập người dùng xác thực
Ở phần trước ta đã bao gồm phần hiển thị thông tin cơ bản của người dùng xác thực. Ngoài name thì bạn cũng có thể lấy thêm các thông tin khác như: email, picture, name, nickname, sub, email_verified, family_name,..
Đối với Server side - (App Router)
Trên server - App Router bạn dùng getSession helper
import { auth0 } from "@/lib/auth0"
export default async function Home() {
const session = await auth0.getSession()
const token = await auth0.getAccessToken()
if (!session) {
return <div>Not authenticated</div>
}
return (
<main>
<h1>Welcome, {session.user.name}!</h1>
</main>
)
}
Đối với Server side - (Pages Router)
Trên server - Pages Router bạn dùng getSession helper
import type { GetServerSideProps, InferGetServerSidePropsType } from "next"
import { auth0 } from "@/lib/auth0"
export const getServerSideProps = (async (ctx) => {
const session = await auth0.getSession(ctx.req)
const token = await auth0.getAccessToken(rectx.req)
if (!session) return { props: { user: null } }
return { props: { user: session.user ?? null } }
}) satisfies GetServerSideProps<{ user: any | null }>
export default function Page({
user,
}: InferGetServerSidePropsType<typeof getServerSideProps>) {
if (!user) {
return (
<main>
<p>Not authenticated!</p>
</main>
)
}
return (
<main>
<p>Welcome, {user.name}!</p>
</main>
)
}
Đối với Client side(App Router)
Trên server bạn dùng hook **useUser() **
"use client"
import { useUser } from "@auth0/nextjs-auth0"
import { getAccessToken } from "@auth0/nextjs-auth0"
export default function Profile() {
const { user, isLoading, error } = useUser()
async function fetchData() {
const token = await getAccessToken()
// call external API with the token...
}
if (isLoading) return <div>Loading...</div>
return (
<main>
<h1>Profile</h1>
<div>
<pre>{JSON.stringify(user, null, 2)}</pre>
</div>
</main>
)
}
Tuỳ chỉnh the SDK client instance
- signInReturnToPath: Đường dẫn chuyển hướng người dùng sau khi xác thực thành công: mặc định sẽ là:
/
Có thể xem thêm tại đây: https://www.npmjs.com/package/@auth0/nextjs-auth0/v/4.0.0-beta.0 -> Mục: **Customizing the client
// src/lib/auth0.ts
import { Auth0Client } from "@auth0/nextjs-auth0/server";
export const auth0 = new Auth0Client({
signInReturnToPath: '/dashboard'
});
Xử lý lỗi
Lỗi - An error occured while trying to initiate the login request.
Nếu bạn gặp lỗi: An error occured while trying to initiate the login request.
Hãy thử thay đổi như sau:
AUTH0_DOMAIN='https://dev-bvgptako.auth0.com'
AUTH0_DOMAIN='dev-bvgptako.auth0.com'
TroubleShooting.
Ngoài ra nếu có lỗi liên quan đến Auth0. hãy thử print: console.log('middleware', auth0);
trong file middleware.ts
để điều tra them
Kết Luận
Bằng cách làm theo các bước này, bạn có thể tích hợp Auth0 hiệu quả vào ứng dụng Next.js của mình, cung cấp trải nghiệm xác thực an toàn và liền mạch cho người dùng của bạn