1Auth0 프로젝트 설정
- auth0.com 에서 계정 생성
- Tenant 생성 (예: my-app.auth0.com)
- Applications → Create Application
- Single Page Web Applications 선택
- Settings에서 다음 설정:
- Allowed Callback URLs:
http://localhost:5173 - Allowed Logout URLs:
http://localhost:5173 - Allowed Web Origins:
http://localhost:5173
- Allowed Callback URLs:
2React 앱 연동
터미널
npm install @auth0/auth0-react환경 변수 설정
.env.local
# .env.local
VITE_AUTH0_DOMAIN=your-tenant.auth0.com
VITE_AUTH0_CLIENT_ID=your-client-id
VITE_AUTH0_AUDIENCE=https://your-api-identifierAuth0Provider 설정
main.tsx
// main.tsx
import React from 'react';
import ReactDOM from 'react-dom/client';
import { Auth0Provider } from '@auth0/auth0-react';
import App from './App';
import './index.css';
ReactDOM.createRoot(document.getElementById('root')!).render(
<React.StrictMode>
<Auth0Provider
domain={import.meta.env.VITE_AUTH0_DOMAIN}
clientId={import.meta.env.VITE_AUTH0_CLIENT_ID}
authorizationParams={{
redirect_uri: window.location.origin,
audience: import.meta.env.VITE_AUTH0_AUDIENCE,
scope: 'openid profile email',
}}
>
<App />
</Auth0Provider>
</React.StrictMode>
);3useAuth0 훅 사용
components/AuthButtons.tsx
// components/AuthButtons.tsx
import { useAuth0 } from '@auth0/auth0-react';
export function AuthButtons() {
const {
isAuthenticated,
isLoading,
user,
loginWithRedirect,
logout,
} = useAuth0();
if (isLoading) {
return <div>로딩 중...</div>;
}
if (isAuthenticated) {
return (
<div className="flex items-center gap-4">
<img
src={user?.picture}
alt={user?.name}
className="w-10 h-10 rounded-full"
/>
<span>{user?.name}</span>
<button
onClick={() => logout({ logoutParams: { returnTo: window.location.origin } })}
className="px-4 py-2 bg-red-600 text-white rounded-lg"
>
로그아웃
</button>
</div>
);
}
return (
<button
onClick={() => loginWithRedirect()}
className="px-4 py-2 bg-blue-600 text-white rounded-lg"
>
로그인
</button>
);
}주요 속성/메서드
isAuthenticated- 로그인 여부isLoading- 인증 상태 로딩 중user- 사용자 프로필 정보loginWithRedirect()- 로그인 페이지로 이동logout()- 로그아웃getAccessTokenSilently()- API 토큰 획득
4보호된 라우트 구현
components/ProtectedRoute.tsx
// components/ProtectedRoute.tsx
import { useAuth0, withAuthenticationRequired } from '@auth0/auth0-react';
// 방법 1: HOC 사용
export const ProtectedPage = withAuthenticationRequired(
function Dashboard() {
const { user } = useAuth0();
return <div>환영합니다, {user?.name}님!</div>;
},
{
onRedirecting: () => <div>리다이렉트 중...</div>,
}
);
// 방법 2: 훅으로 직접 체크
export function ProtectedContent({ children }: { children: React.ReactNode }) {
const { isAuthenticated, isLoading, loginWithRedirect } = useAuth0();
if (isLoading) return <div>로딩 중...</div>;
if (!isAuthenticated) {
loginWithRedirect();
return <div>로그인 페이지로 이동 중...</div>;
}
return <>{children}</>;
}5백엔드 API 연동
API 호출 시 Access Token을 포함해야 합니다.
hooks/useApi.ts
// hooks/useApi.ts
import { useAuth0 } from '@auth0/auth0-react';
export function useApi() {
const { getAccessTokenSilently } = useAuth0();
const fetchWithToken = async (url: string, options: RequestInit = {}) => {
const token = await getAccessTokenSilently({
authorizationParams: {
audience: import.meta.env.VITE_AUTH0_AUDIENCE,
},
});
return fetch(url, {
...options,
headers: {
...options.headers,
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json',
},
});
};
return { fetchWithToken };
}
// 사용 예시
function ProjectList() {
const { fetchWithToken } = useApi();
const [projects, setProjects] = useState([]);
useEffect(() => {
fetchWithToken('/api/projects')
.then(res => res.json())
.then(data => setProjects(data));
}, []);
return <ul>{projects.map(p => <li key={p.id}>{p.name}</li>)}</ul>;
}백엔드에서 토큰 검증
server.js
// 백엔드 (Node.js/Express 예시)
import { expressjwt } from 'express-jwt';
import jwksRsa from 'jwks-rsa';
const checkJwt = expressjwt({
secret: jwksRsa.expressJwtSecret({
cache: true,
rateLimit: true,
jwksRequestsPerMinute: 5,
jwksUri: `https://${process.env.AUTH0_DOMAIN}/.well-known/jwks.json`,
}),
audience: process.env.AUTH0_AUDIENCE,
issuer: `https://${process.env.AUTH0_DOMAIN}/`,
algorithms: ['RS256'],
});
// 보호된 API 엔드포인트
app.get('/api/protected', checkJwt, (req, res) => {
// req.auth에 토큰 정보가 담겨있음
res.json({ userId: req.auth.sub });
});6역할 기반 접근 제어 (RBAC)
Auth0의 RBAC 기능을 사용하면 사용자별로 권한을 관리할 수 있습니다.
RBAC 설정
// Auth0 대시보드에서 역할(Role) 생성 후,
// 토큰에 역할 정보를 포함하도록 Rule 추가
// Auth0 Rule (Actions 또는 Rules에서 설정)
exports.onExecutePostLogin = async (event, api) => {
const namespace = 'https://your-app.com';
if (event.authorization) {
api.idToken.setCustomClaim(`${namespace}/roles`, event.authorization.roles);
api.accessToken.setCustomClaim(`${namespace}/roles`, event.authorization.roles);
}
};
// React에서 역할 확인
function AdminPanel() {
const { user, isAuthenticated } = useAuth0();
const roles = user?.['https://your-app.com/roles'] || [];
const isAdmin = roles.includes('admin');
if (!isAdmin) {
return <div>관리자 권한이 필요합니다.</div>;
}
return <div>관리자 패널</div>;
}정보
Auth0 대시보드에서 User Management → Roles에서 역할을 생성하고 사용자에게 할당할 수 있습니다.