0

Auth0 Bài 5: Tích hợp Auth0 cho Single Page App (React) bằng luồng Authorization Code với PKCE.

Chào mừng bạn đến với Bài 5! Đây là lúc chúng ta biến lý thuyết thành những dòng code chạy thực tế. Như đã học ở bài trước, React là một Single Page Application (SPA) chạy hoàn toàn trên trình duyệt, nên chúng ta bắt buộc phải dùng luồng Authorization Code với PKCE.

Tin vui là: Bạn không cần phải tự viết code tạo hay băm các chuỗi mã hóa phức tạp. Thư viện chính thức @auth0/auth0-react của Auth0 sẽ "bao thầu" toàn bộ quy trình PKCE ở dưới nền (under the hood). Việc của bạn chỉ là gọi hàm.

Cùng bắt tay vào làm nhé!


1. Chuẩn bị (Sanity Check)

Trước khi code, hãy chắc chắn bạn đã làm 2 việc này trên Auth0 Dashboard (trong mục Applications > Applications > Ứng dụng SPA của bạn):

  • Copy Domain và Client ID.
  • Đảm bảo cấu hình các URL sau là http://localhost:3000 (hoặc cổng mà React của bạn đang chạy, ví dụ Vite thường dùng 5173):
    • Allowed Callback URLs
    • Allowed Logout URLs
    • Allowed Web Origins

Tạo một file .env ở thư mục gốc của dự án React và dán 2 thông số trên vào:

# Nếu bạn dùng Create React App:
REACT_APP_AUTH0_DOMAIN=dev-xxx.us.auth0.com
REACT_APP_AUTH0_CLIENT_ID=your_client_id_here

# Nếu bạn dùng Vite:
VITE_AUTH0_DOMAIN=dev-xxx.us.auth0.com
VITE_AUTH0_CLIENT_ID=your_client_id_here

2. Cài đặt SDK và bọc ứng dụng bằng Auth0Provider

Mở terminal tại thư mục dự án React và chạy lệnh:

npm install @auth0/auth0-react

Để mọi Component trong React đều biết được trạng thái "User đã đăng nhập hay chưa", chúng ta cần bọc toàn bộ ứng dụng bằng Auth0Provider (sử dụng React Context API).

Mở file index.js (hoặc main.jsx nếu dùng Vite) và sửa lại như sau:

import React from 'react';
import { createRoot } from 'react-dom/client';
import { Auth0Provider } from '@auth0/auth0-react';
import App from './App';

const root = createRoot(document.getElementById('root'));

// Lấy biến môi trường (ví dụ dưới đây dùng cú pháp của Create React App)
const domain = process.env.REACT_APP_AUTH0_DOMAIN;
const clientId = process.env.REACT_APP_AUTH0_CLIENT_ID;

root.render(
  <Auth0Provider
    domain={domain}
    clientId={clientId}
    authorizationParams={{
      redirect_uri: window.location.origin // Nơi Auth0 trả user về sau khi login
    }}
  >
    <App />
  </Auth0Provider>
);

3. Tạo nút Đăng nhập và Đăng xuất

Thư viện cung cấp cho chúng ta một custom hook cực kỳ mạnh mẽ tên là useAuth0. Hook này chứa mọi thứ bạn cần.

Tạo file LoginButton.jsx:

import React from "react";
import { useAuth0 } from "@auth0/auth0-react";

const LoginButton = () => {
  // Hàm loginWithRedirect sẽ tự động sinh mã PKCE và chuyển hướng user sang Auth0
  const { loginWithRedirect } = useAuth0();

  return <button onClick={() => loginWithRedirect()}>Đăng nhập</button>;
};

export default LoginButton;

Tạo file LogoutButton.jsx:

import React from "react";
import { useAuth0 } from "@auth0/auth0-react";

const LogoutButton = () => {
  // Khi logout, Auth0 sẽ xóa phiên làm việc và trả user về trang chủ (origin)
  const { logout } = useAuth0();

  return (
    <button onClick={() => logout({ logoutParams: { returnTo: window.location.origin } })}>
      Đăng xuất
    </button>
  );
};

export default LogoutButton;

4. Hiển thị thông tin người dùng (Profile)

Làm sao để biết người dùng tên gì, avatar ra sao? Lại là hook useAuth0!

Tạo file Profile.jsx:

import React from "react";
import { useAuth0 } from "@auth0/auth0-react";

const Profile = () => {
  // Lấy ra thông tin user, trạng thái xác thực, và trạng thái đang tải dữ liệu
  const { user, isAuthenticated, isLoading } = useAuth0();

  if (isLoading) {
    return <div>Đang tải...</div>;
  }

  // Nếu chưa đăng nhập thì không render gì cả
  if (!isAuthenticated) {
    return null;
  }

  // Nếu đã đăng nhập, hiển thị thông tin
  return (
    <div style={{ marginTop: "20px", padding: "20px", border: "1px solid #ccc" }}>
      <img src={user.picture} alt={user.name} style={{ borderRadius: "50%", width: "100px" }} />
      <h2>Xin chào, {user.name}!</h2>
      <p>Email của bạn là: {user.email}</p>
      
      <h3>Dữ liệu JSON gốc từ ID Token:</h3>
      <pre style={{ textAlign: "left", background: "#f4f4f4", padding: "10px" }}>
        {JSON.stringify(user, null, 2)}
      </pre>
    </div>
  );
};

export default Profile;

5. Ghép nối tất cả vào App.jsx

Cuối cùng, mở file App.jsx và sắp xếp các Component lại:

import React from 'react';
import { useAuth0 } from '@auth0/auth0-react';
import LoginButton from './LoginButton';
import LogoutButton from './LogoutButton';
import Profile from './Profile';

function App() {
  const { isAuthenticated } = useAuth0();

  return (
    <div style={{ textAlign: "center", padding: "50px" }}>
      <h1>Ứng dụng React bảo mật với Auth0</h1>
      
      {/* Cấu trúc điều kiện: Chưa login thì hiện nút Đăng nhập, Login rồi thì hiện Đăng xuất */}
      {!isAuthenticated ? <LoginButton /> : <LogoutButton />}
      
      <Profile />
    </div>
  );
}

export default App;

💡 Tổng kết

Chạy lệnh npm start (hoặc npm run dev) và trải nghiệm thử! Khi bạn bấm Đăng nhập, nó sẽ bay sang trang Login rất xịn xò của Auth0, sau đó trả về trang của bạn với đầy đủ Avatar và Email. Quá trình băm chuỗi PKCE đã diễn ra âm thầm và hoàn hảo.


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí