209 lines
8.1 KiB
Markdown
209 lines
8.1 KiB
Markdown
# Authentication Documentation
|
|
|
|
This document explains the authentication setup for the App.
|
|
|
|
## OIDC Authentication
|
|
|
|
The application uses OpenID Connect (OIDC) for authentication with the following features:
|
|
|
|
- Dynamic configuration loading from API endpoint `/oidc.json`
|
|
- Token storage in localStorage via WebStorageStateStore
|
|
- Automatic token refresh with silent renewal
|
|
- Refresh token support via offline_access scope
|
|
- Protected routes with role-based access control
|
|
- Smart authentication flow with auto-login and manual logout tracking
|
|
|
|
### Configuration
|
|
|
|
The OIDC configuration is fetched from the API endpoint `/oidc.json`. This endpoint should return a JSON object with the following structure:
|
|
|
|
```json
|
|
{
|
|
"authorityUrl": "https://your-oidc-provider.com",
|
|
"clientId": "your-client-id"
|
|
}
|
|
```
|
|
|
|
The application requires the `CLIENT_API_URL` environment variable to be set to the base URL of the API server. The OIDC configuration is then fetched from `${CLIENT_API_URL}/oidc.json` using the OidcService.
|
|
|
|
#### OIDC Client Configuration
|
|
|
|
The application configures the OIDC client with the following settings:
|
|
|
|
```typescript
|
|
{
|
|
authority: config.authorityUrl,
|
|
client_id: config.clientId,
|
|
redirect_uri: `${window.location.origin}/auth/callback`,
|
|
response_type: "code",
|
|
scope: "openid profile email offline_access", // offline_access for refresh tokens
|
|
post_logout_redirect_uri: window.location.origin,
|
|
userStore: new WebStorageStateStore({ store: window.localStorage }),
|
|
loadUserInfo: true,
|
|
automaticSilentRenew: true,
|
|
revokeTokensOnSignout: true,
|
|
monitorSession: true,
|
|
}
|
|
```
|
|
|
|
Key configuration details:
|
|
- `offline_access` scope is requested to enable refresh tokens
|
|
- `automaticSilentRenew` is enabled to automatically refresh tokens in the background
|
|
- `revokeTokensOnSignout` ensures tokens are properly revoked when logging out
|
|
- `monitorSession` enables session monitoring to detect changes
|
|
|
|
### Authentication Flow
|
|
|
|
#### Initial Authentication
|
|
|
|
1. The `AuthProvider` component initializes the `UserManager` from `oidc-client-ts` using the configuration fetched from the API endpoint `/oidc.json`.
|
|
2. It checks if the user is already authenticated by calling `userManager.getUser()`.
|
|
3. If a user is found but the token is expired or about to expire, it attempts a silent token renewal.
|
|
4. If no user is found and the user has not manually logged out (tracked in localStorage), the app automatically initiates the login process.
|
|
5. The login process first tries silent login (`userManager.signinSilent()`).
|
|
6. If silent login fails, it falls back to redirect login (`userManager.signinRedirect()`).
|
|
7. After successful authentication at the provider, the user is redirected back to the application's callback URL (`/auth/callback`).
|
|
8. The `AuthCallback` component handles the redirect, processes the response, and stores the user session.
|
|
|
|
#### Token Renewal
|
|
|
|
1. The application uses `automaticSilentRenew` to automatically refresh tokens in the background.
|
|
2. When a token is about to expire, the OIDC client attempts a silent renewal.
|
|
3. If silent renewal fails, the application will detect this during API calls and can redirect to login if needed.
|
|
|
|
#### Manual vs. Auto Login
|
|
|
|
The application implements a smart authentication flow that distinguishes between first visits and visits after manual logout:
|
|
|
|
1. **First Visit or Regular Visit**: The app automatically initiates the login process.
|
|
2. **After Manual Logout**: The app requires the user to click the "Sign in" button to log in again.
|
|
|
|
This behavior is controlled by a `manuallyLoggedOut` flag that is:
|
|
- Stored in localStorage to persist across page refreshes and browser sessions
|
|
- Set to `true` when the user manually logs out
|
|
- Reset to `false` when the user successfully logs in or manually clicks the login button
|
|
|
|
### Protected Routes
|
|
|
|
Routes that require authentication can be protected using the `ProtectedRoute` component:
|
|
|
|
```jsx
|
|
import { ProtectedRoute } from '@domains/auth'; // Adjusted path based on current structure
|
|
|
|
// Basic protection
|
|
<ProtectedRoute>
|
|
<YourComponent />
|
|
</ProtectedRoute>
|
|
|
|
// With role-based protection
|
|
<ProtectedRoute requiredRoles={['admin']}>
|
|
<AdminComponent />
|
|
</ProtectedRoute>
|
|
```
|
|
|
|
### Making Authenticated API Calls
|
|
|
|
Use the `useApiService` hook (now located in `src/shared/lib/api/apiService.ts`) to make API calls.
|
|
|
|
```jsx
|
|
import { useApiService } from '@shared/lib/api'; // Use the alias
|
|
|
|
function YourComponent() {
|
|
const api = useApiService();
|
|
|
|
const fetchData = async () => {
|
|
const response = await api.get('/your-endpoint');
|
|
const data = await response.json();
|
|
// Process data
|
|
};
|
|
|
|
// ...
|
|
}
|
|
```
|
|
|
|
The current simplified `useApiService` hook:
|
|
- Checks if the user is authenticated using `useAuth`.
|
|
- **Does not** automatically add the access token to requests (this would need to be added if required by the backend).
|
|
- **Does not** handle token refresh or expiration explicitly. It relies on the underlying `oidc-client-ts` library's session management.
|
|
- Logs an error if a 401 Unauthorized response is received.
|
|
|
|
### Logout
|
|
|
|
To log a user out, use the `logout` function returned by the `useAuth` hook. This function triggers the `logoutFx` effect, which performs the following steps:
|
|
|
|
1. Sets the `manuallyLoggedOut` flag to `true` in localStorage
|
|
2. Clears the user from the store
|
|
3. Initiates the OIDC sign-out redirect flow via `userManager.signoutRedirect()`
|
|
|
|
The logout process is designed to ensure that the user remains logged out even after page refreshes or browser restarts, until they explicitly choose to log in again.
|
|
|
|
```jsx
|
|
import { useAuth } from '@domains/auth';
|
|
|
|
function LogoutButton() {
|
|
const { logout, user } = useAuth();
|
|
|
|
return (
|
|
<button
|
|
onClick={logout}
|
|
className="px-4 py-2 bg-[#653cee] hover:bg-[#4e2eb8] text-white rounded-md"
|
|
>
|
|
Logout
|
|
</button>
|
|
);
|
|
}
|
|
```
|
|
|
|
The `logoutFx` effect is configured to revoke tokens on signout using the `revokeTokensOnSignout: true` setting in the OIDC client configuration. This ensures that tokens are properly invalidated when logging out.
|
|
|
|
## Troubleshooting
|
|
|
|
### Common Issues
|
|
|
|
1. **Authentication configuration error**
|
|
- Check that the API endpoint `/oidc.json` is accessible
|
|
- Verify that the API returns the correct JSON structure with `authorityUrl` and `clientId` fields
|
|
- Ensure the `CLIENT_API_URL` environment variable is correctly set
|
|
|
|
2. **Token refresh failures**
|
|
- Check that the OIDC server is configured to allow refresh tokens
|
|
- Verify that the `offline_access` scope is included in the OIDC configuration
|
|
- Check browser console for silent renewal errors
|
|
|
|
3. **CORS errors**
|
|
- Ensure the OIDC server has the correct origins configured
|
|
- Check that redirect URIs are properly set up
|
|
- Verify that the OIDC server allows the application's origin
|
|
|
|
4. **Auto-login not working**
|
|
- Check if the `auth_manually_logged_out` flag in localStorage is set to `true`
|
|
- Clear the flag by setting it to `false` or removing it from localStorage
|
|
- Verify that the user doesn't have an existing session that's invalid
|
|
|
|
5. **Logout not working properly**
|
|
- Check browser console for errors during the logout process
|
|
- Verify that the `revokeTokensOnSignout` setting is enabled
|
|
- Check if the OIDC server is properly configured to handle logout requests
|
|
|
|
### Debugging
|
|
|
|
The application includes extensive logging to help diagnose authentication issues:
|
|
|
|
1. **Check localStorage**: The application stores authentication state in localStorage:
|
|
- `auth_manually_logged_out`: Tracks if the user has manually logged out
|
|
- `oidc.user:[authority]:[client_id]`: Contains the user session data
|
|
|
|
2. **Console Logging**: The application logs detailed information about the authentication process:
|
|
- Authentication initialization and configuration
|
|
- Token validation and renewal attempts
|
|
- Login and logout operations
|
|
- State changes in the authentication store
|
|
|
|
3. **Enable Debug Mode**: For even more detailed logging, enable debug mode by setting the `CLIENT_DEBUG` environment variable to `true` in your `.env` file:
|
|
|
|
```
|
|
CLIENT_DEBUG=true
|
|
```
|
|
|
|
This enables additional logging in various parts of the application, including more detailed OIDC client logs.
|