Integration
This guide explains how product teams can integrate Auth0 authentication into their React applications.
Pre-requisites
-
Ensure the product is registered with Aventian.
-
Request the following values from the Aventian Team:
domainclientIdaudience
-
Ask Aventian Team to add your product URLs into Auth0 allowed URLs.
Installation
Install the Auth0 React SDK:
npm install @auth0/auth0-react
Setup Auth0 Outlet
import { AppState, Auth0Provider } from '@auth0/auth0-react';
import { Outlet, useNavigate } from 'react-router-dom';
const Auth0Outlet = () => {
const navigate = useNavigate();
const onRedirectCallback = (appState?: AppState) => {
console.log(appState);
navigate(appState?.returnTo ?? window.location.pathname);
};
return (
<Auth0Provider
domain={import.meta.env.VITE_APP_AUTH0_DOMAIN}
clientId={import.meta.env.VITE_APP_AUTH0_CLIENT_ID}
authorizationParams={{
redirect_uri: window.location.origin,
audience: import.meta.env.VITE_APP_AUTH0_AUDIENCE,
}}
onRedirectCallback={onRedirectCallback}
>
<Outlet />
</Auth0Provider>
);
};
export default Auth0Outlet;
Add Auth0 Outlet to Root Router
import {
createBrowserRouter,
createRoutesFromElements,
RouterProvider,
Route,
} from 'react-router';
import {
ErrorBoundary,
NotFound,
} from '@modules/shared/components/index';
import {
Auth0Outlet,
PublicOutlet,
SecuredOutlet,
} from '@routes/outlets/index';
const router = createBrowserRouter(
createRoutesFromElements(
<Route errorElement={<ErrorBoundary />}>
<Route path="/" element={<Auth0Outlet />}>
<Route path="/" element={<SecuredOutlet />}>
<Route path="private" element={<div>Private</div>} />
</Route>
<Route path="/" element={<PublicOutlet />}>
<Route path="public" element={<div>Public</div>} />
</Route>
<Route path="*" element={<NotFound />} />
</Route>
</Route>,
),
);
export default function AppRoute() {
return <RouterProvider router={router} />;
}
Securing Routes with useAuth0
import { useAuth0 } from '@auth0/auth0-react';
import React, { useEffect } from 'react';
import { Outlet } from 'react-router';
import { Spin } from 'antd';
import { LoadingOutlined } from '@ant-design/icons';
const onRedirectingLoader = () => {
return <Spin spinning={true} fullscreen={true}></Spin>;
};
const SecuredOutlet: React.FC = () => {
const {
isLoading,
isAuthenticated,
loginWithRedirect,
} = useAuth0();
useEffect(() => {
if (!isLoading && !isAuthenticated) {
loginWithRedirect({
appState: {
returnTo: location.pathname + location.search,
onRedirecting: () => onRedirectingLoader(),
},
});
}
}, [isLoading, isAuthenticated]);
return (
<Spin
indicator={<LoadingOutlined style={{ fontSize: 24 }} spin />}
spinning={isLoading || !isAuthenticated}
fullscreen={isLoading || !isAuthenticated}
>
{!isLoading &&
isAuthenticated && <Outlet />}
</Spin>
);
};
export default SecuredOutlet;
Logout
For logout, use the Aventian React library: 👉 Profile Dropdown Widget
Token Verification (Frontend)
Use the Aventian-provided API for verifying tokens and fetching user details: 👉 User Details API
Code Example
Node JS
const axios = require('axios');
async function getUserDetails() {
try {
const response = await axios.get(
'https://aventian.uc.r.appspot.com/api/v2/auth/get-user-details',
{
headers: {
'accept': 'application/json',
'Authorization': 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOiIxMjM0NTYiLCJyb2xlIjoiZGVtbzEiLCJleHAiOjE3MDAwMDAwMDB9.abc123XYZ456fakeSignature789'
}
}
);
console.log(response.data);
} catch (error) {
console.error('Error:', error.response ? error.response.data : error.message);
}
}
getUserDetails();
Python
import requests
url = "https://aventian.uc.r.appspot.com/api/v2/auth/get-user-details"
headers = {
"accept": "application/json",
"Authorization": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOiIxMjM0NTYiLCJyb2xlIjoiZGVtbzEiLCJleHAiOjE3MDAwMDAwMDB9.abc123XYZ456fakeSignature789"
}
response = requests.get(url, headers=headers)
print(response.json())
Response
{
"id": 1233,
"name": "Json Holder",
"email": "json.holder@gmail.com",
"profile_picture": "https://toppng.com/uploads/preview/gravatar-logo-11609363449s2hnzzbhe9.png",
"team_id": 1,
"team_name": "Dummy Team",
"team_key": "dummy",
"api_key": "X-API-KEY",
"roles": [
{
"id": 3,
"name": "Admin",
"product_id": 2,
"description": "Built-in Role"
}
],
"team_logo": "https://toppng.com/uploads/preview/gravatar-logo-11609363449s2hnzzbhe9.png",
"team_owner_id": 3,
"permissions": [
"project:color:own",
"project:favourite:own",
"project:folder:manage",
"team:all:projects",
"team:notification:manage",
"team:project:create",
"team:settings:customfields:create",
"team:settings:customfields:delete",
"team:settings:customfields:edit",
"team:settings:customfields:view",
"team:settings:optionalfields:edit",
"team:settings:view"
]
}
Request Authentication & Authorization (Backend)
Use the Aventian-provided API for verifying tokens and X-API-Key to authorize requests: 👉 Verify User Request API
Code Example
Node JS
const axios = require('axios');
async function verifyAuth() {
try {
const response = await axios.get(
'https://aventian.uc.r.appspot.com/api/v2/auth/verify',
{
headers: {
'accept': '*/*',
'X-Api-Key': 'X-API-KEY',
'Authorization': 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOiIxMjM0NTYiLCJyb2xlIjoiZGVtbzEiLCJleHAiOjE3MDAwMDAwMDB9.abc123XYZ456fakeSignature789'
}
}
);
console.log(response.data);
} catch (error) {
console.error('Error:', error.response ? error.response.data : error.message);
}
}
verifyAuth();
Python
import requests
url = "https://aventian.uc.r.appspot.com/api/v2/auth/verify"
headers = {
"accept": "*/*",
"X-Api-Key": "X-API-KEY",
"Authorization": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOiIxMjM0NTYiLCJyb2xlIjoiZGVtbzEiLCJleHAiOjE3MDAwMDAwMDB9.abc123XYZ456fakeSignature789"
}
response = requests.get(url, headers=headers)
print(response.json())
Response
{
"id": 1233,
"name": "Json Holder",
"email": "json.holder@gmail.com",
"roles": [
{
"id": 3,
"name": "Admin",
"description": "Built-in Role"
}
],
"api_key": "X-API-KEY",
"team_id": 4,
"team_key": "dummy",
"team_name": "Dummy Team",
"permissions": [
"project:color:own",
"project:favourite:own",
"project:folder:manage",
"team:all:projects",
"team:notification:manage",
"team:project:create",
"team:settings:customfields:create",
"team:settings:customfields:delete",
"team:settings:customfields:edit",
"team:settings:customfields:view",
"team:settings:optionalfields:edit",
"team:settings:view"
],
"encrypted_team_db_config": "U2FsdGVkX19Lzb3NGIDCEALhW8ckwJ5UHGU497IzhNOK/LFkSX4rZNudjqoL10mdqdhDy+DT7YzIQNFd/1vXxNv4lYtpEtEo/Qc+ZOWXZX9Pwn5dNJzESvUnfzcqsix/KrqnFfF6xIgKOq1F3xs/6LzicsulN5rdPakqPOWVIARHVn4VQ8inCqQwgiVLecZ52qFFp4uG1Wknn9YoPZGohysAqEy4Xpc3V3HKwzqRhG9n",
"cache_hit": true
}
The service ensures the provided token and API key are both valid and associated with the same user and team.
Summary & Next Steps
You're now set up to:
- Authenticate users via Auth0 in a React SPA.
- Protect routes with a secure outlet pattern.
- Retrieve user profile + roles/permissions via the User Details API.
- Server‑side verify requests with both JWT (Authorization header) and X-Api-Key for defense in depth.
Recommended next steps:
- Implement refresh / silent auth flows (Auth0
getAccessTokenSilently). - Cache user + permission data client-side with a short TTL to reduce network calls.
- Enforce permission checks in UI components (e.g. feature flags / guard hooks).
- Add backend middleware to centralize verify + permission mapping.
- Rotate API keys periodically and monitor for unusual usage.
Troubleshooting
| Issue | Hint |
|---|---|
| Infinite redirect loop | Ensure callback URL is whitelisted in Auth0 and returnTo path exists. |
| 401 from verify endpoint | Token expired or audience mismatch—confirm Auth0 API audience value. |
| 403 after verify | API key valid but missing required role/permission—inspect permissions array. |