@nettie/franklin-id
v0.1.2
Published
React component library for easily integrating Franklin/Genoox authentication (using Auth0) into your application.
Readme
Franklin ID Auth Component (@nettie/franklin-id)
React component library for easily integrating Franklin/Genoox authentication (using Auth0) into your application.
Installation
npm install @nettie/franklin-id # or yarn add @nettie/franklin-id, or bun install @nettie/franklin-id
# Make sure you have react and react-dom installed as peer dependencies
npm install react react-domPrerequisites
Before using this component, ensure you have:
- Configured an Auth0 Application: Set up an application in your Auth0 dashboard (likely a Single Page Application type).
- Configured an Auth0 API: Set up an API in Auth0 that your application will interact with (e.g.,
https://genoox.eu.auth0.com/api/v2/). Note its API Audience identifier. - Registered Callback URL: You need a backend endpoint (like the provided Supabase function example) that handles the OAuth code exchange. Add the URL of this backend endpoint (e.g.,
https://<your-project-ref>.supabase.co/functions/v1/auth-callback) to the "Allowed Callback URLs" in your Auth0 Application settings. - Obtained Credentials: Note down your Auth0 Domain, Client ID, and the API Audience identifier.
Usage
Import the FranklinAuth component using a default import and provide the necessary configuration props.
import React, { useState } from 'react';
// Correct: Use a default import
import FranklinAuth from '@nettie/franklin-id';
// Configuration - Load sensitive values from environment variables or a config service
const AUTH0_DOMAIN = process.env.REACT_APP_AUTH0_DOMAIN || 'your-auth0-domain.auth0.com';
const AUTH0_CLIENT_ID = process.env.REACT_APP_AUTH0_CLIENT_ID || 'your_auth0_client_id';
// This MUST be the URL of your backend handler (e.g., Supabase function) registered in Auth0
const AUTH0_CALLBACK_URL = process.env.REACT_APP_AUTH0_CALLBACK_URL || 'https://<your-project-ref>.supabase.co/functions/v1/auth-callback';
const API_AUDIENCE = process.env.REACT_APP_API_AUDIENCE || 'https://your-api-audience.com/'; // Your Auth0 API Audience
function YourApplication() {
const [isAuthenticated, setIsAuthenticated] = useState(false);
const [userProfile, setUserProfile] = useState<any>(null); // Store decoded ID token claims
const [accessToken, setAccessToken] = useState<string | null>(null);
const [authError, setAuthError] = useState<any>(null);
// Function to parse ID token (basic example, use a library like jwt-decode for robustness)
const parseJwt = (token: string) => {
try {
// Basic validation: check for 3 parts separated by dots
if (token.split('.').length !== 3) return null;
return JSON.parse(atob(token.split('.')[1]));
} catch (e) {
console.error("Error parsing JWT:", e);
return null;
}
};
const handleLoginSuccess = (tokens: { idToken: string, accessToken: string }) => {
console.log("Authentication successful!");
setIsAuthenticated(true);
setAccessToken(tokens.accessToken); // Store access token in state (IMPORTANT: See token handling section)
setUserProfile(parseJwt(tokens.idToken)); // Decode ID token for user info
setAuthError(null);
// Now you can use the accessToken to call your protected API
// fetch('https://your.api.com/data', {
// headers: { Authorization: `Bearer ${tokens.accessToken}` }
// }).then(...)
};
const handleLoginFailure = (error: any) => {
console.error("Authentication failed:", error);
setIsAuthenticated(false);
setAccessToken(null);
setUserProfile(null);
setAuthError(error);
};
const handleLogout = () => {
// Basic logout: clear local state
setIsAuthenticated(false);
setAccessToken(null);
setUserProfile(null);
setAuthError(null);
// TODO: Implement full logout by redirecting to Auth0 logout endpoint
// const logoutUrl = `https://${AUTH0_DOMAIN}/v2/logout?client_id=${AUTH0_CLIENT_ID}&returnTo=${window.location.origin}`;
// window.location.href = logoutUrl;
};
return (
<div>
<h1>My Application</h1>
{!isAuthenticated ? (
<div>
<p>Please log in.</p>
<FranklinAuth
auth0Domain={AUTH0_DOMAIN}
clientId={AUTH0_CLIENT_ID}
redirectUri={AUTH0_CALLBACK_URL} // Your backend callback handler URL
audience={API_AUDIENCE} // Your Auth0 API Audience
onAuthSuccess={handleLoginSuccess}
onAuthFailure={handleLoginFailure}
// Optionally provide custom scopes or state:
// scope="openid profile email read:custom_scope"
// state="your_secure_random_state_value"
/>
{authError && <p style={{ color: 'red' }}>Error: {authError.error_description || authError.error || 'Login failed'}</p>}
</div>
) : (
<div>
<h2>Welcome, {userProfile?.name || 'User'}!</h2>
{userProfile?.picture && (
<img src={userProfile.picture} alt="Profile" width="50" style={{ borderRadius: '50%' }} />
)}
<p>You are logged in.</p>
<button onClick={handleLogout}>Logout</button>
{/* Display Access Token for debugging (REMOVE in production) */}
{accessToken && (
<div style={{ marginTop: '10px', wordBreak: 'break-all' }}>
<strong>Access Token:</strong> <small>{accessToken}</small>
</div>
)}
{/* Add components that need the access token here */}
{/* Example: <UserProfileEditor accessToken={accessToken} /> */}
</div>
)}
</div>
);
}
export default YourApplication;Component Props
| Prop | Type | Required | Description |
|------------------|---------------------------------------------------------|----------|-------------------------------------------------------------------------------------------------------------------------------------------|
| auth0Domain | string | Yes | Your Auth0 tenant domain (e.g., your-tenant.auth0.com). |
| clientId | string | Yes | The Client ID of your Auth0 Application. |
| redirectUri | string | Yes | The URL of your backend callback handler (e.g., Supabase function) that Auth0 should redirect to after login. This URL must be registered in your Auth0 Application's "Allowed Callback URLs". |
| audience | string | Yes | The unique identifier (API Audience) of the API registered in Auth0 that you want to get an Access Token for. |
| onAuthSuccess | (tokens: { idToken: string, accessToken: string }) => void | Yes | Callback function executed on successful authentication. Receives an object containing the idToken and accessToken. |
| onAuthFailure | (error: any) => void | Yes | Callback function executed on authentication failure. Receives the error object from Auth0. |
| scope | string | No | Optional. Space-separated list of OAuth scopes to request. Defaults to extensive Franklin/Genoox scopes. Override if specific permissions are needed. |
| state | string | No | Optional. A random string used for CSRF protection. If provided, your backend callback handler should generate and verify it. Defaults to a placeholder (implement proper state handling for production). |
Handling Tokens
idToken(ID Token):- A JSON Web Token (JWT) containing claims about the authenticated user (e.g., name, email, picture).
- Intended for the client application (your React app) to understand who the user is.
- Can be decoded client-side to display user profile information.
- Auth0 validates this token during the code exchange in your backend callback handler.
accessToken(Access Token):- A token (often a JWT, but can be opaque) that proves the user has authorized your application to access specific resources on their behalf (defined by the
scoperequested). - Intended for the Resource Server (your target API, e.g.,
https://franklin.genoox.com/api/v2/...). - Crucially, include this token in the
Authorization: Bearer <accessToken>header when making requests from your application (or your backend) to your protected API. - Security: Do NOT store Access Tokens in
localStorageorsessionStoragedue to vulnerability to XSS attacks. Store them securely in application memory (React state, Context API, Redux, etc.) for the duration needed. Fetch new tokens when the application loads or the previous token expires (Auth0 handles session management to facilitate this).
- A token (often a JWT, but can be opaque) that proves the user has authorized your application to access specific resources on their behalf (defined by the
Development (of this package)
This package contains only the library code. For testing and development:
- Clone this repository.
- Install dependencies:
bun install - Build the package:
bun run build - Link the package locally:
npm link(orbun link) - In a separate test application (like the
test-auth-appexample), link the package:npm link @nettie/franklin-id(orbun link @nettie/franklin-id). - Run the test application's development server (e.g.,
bun run dev). Changes in thefranklin-idpackage will require rebuilding (bun run build) to be reflected in the test app.
# Example workflow:
# In ./franklin-id directory:
bun install
bun run build
npm link # Or bun link
# In ../test-auth-app directory:
bun install
npm link @nettie/franklin-id # Or bun link @nettie/franklin-id
bun run dev