HTTP React
1. DNext React HTTP¶
@dnext-react/http is a library that simplifies authentication with Keycloak in React applications. It provides a DNextOidcProvider component that wraps your application and manages the Keycloak instance. The package also includes an httpClient instance that automatically attaches the authentication token to HTTP requests.
- 1. DNext React HTTP
- 2. Import and Configure DNextOidcProvider
- 2.1. Import DNextOidcProvider
- 2.3. Wrap Your Application with DNextOidcProvider
- 3. Use the useAuth Hook
- 3.1. Import useAuth
- 3.2. Use the Hook in a Component
- 4. Make Authenticated HTTP Requests
- 4.1. Import httpClient
- 4.2. Make Requests
- 5. Protect Routes
- 5.1. Create a Protected Route Component
- 5.2. Use the Protected Route
- 6. Access User Information
- 6.1. Retrieve User Profile
- 7. Handle Token Refresh and Errors
- 7.1. Customize Axios Interceptors
- 8. Ensure Singleton Keycloak Instance
- 8.1. Use the Provided
getKeycloakInstanceFunction - 9. Environment Configuration
- 9.1. Use Environment Variables
- 10. Conclusion
2. Import and Configure DNextOidcProvider¶
The DNextOidcProvider component from @dnext-react/http wraps your application and provides Keycloak authentication context to all child components.
2.1. Import DNextOidcProvider¶
In your main application file (e.g., src/App.tsx or src/index.tsx), import the DNextOidcProvider:
import React from 'react';
import ReactDOM from 'react-dom';
import { DNextOidcProvider } from '@dnext-react/http';
import App from './App';
2.2. Configure Keycloak Define your Keycloak configuration object. This configuration should match the settings of your Keycloak server:
const keycloakConfig = {
authority: 'https://your-keycloak-domain/auth/realms/your-realm',
client_id: 'your-client-id',
redirect_uri: window.location.origin + window.location.pathname.replace(/\/$/, ''),
post_logout_redirect_uri: window.location.origin,
response_type: 'code',
scope: 'openid',
automaticSilentRenew: true,
disablePKCE: true,
loadUserInfo: true,
};
authority: The URL of the OIDC/OAuth2 provider.client_id: Your client application's identifier as registered with the OIDC/OAuth2.redirect_uri: The redirect URI of your client application to receive a response from the OIDC/OAuth2 providerpost_logout_redirect_uri: The OIDC/OAuth2 post-logout redirect URIresponse_type: The type of response expected from the OIDC/OAuth2 provider.scope: The scope of the access request.automaticSilentRenew: Whether to automatically renew the access token.disablePKCE: Whether to disable Proof Key for Code Exchange (PKCE).loadUserInfo: Whether to load user information after login.
2.3. Wrap Your Application with DNextOidcProvider¶
Wrap your application with the DNextOidcProvider, passing in the configuration:
ReactDOM.render(
<DNextOidcProvider userManager={keycloakConfig} onSigninCallback={onSigninCallback}>
<App />
</DNextOidcProvider>,
document.getElementById('root')
);
import React from 'react';
import DNextOidcProvider from '@dnext-react/http/src/DNextOidcProvider';
import { onSigninCallback } from '@dnext-react/http';
const App: React.FC = () => {
const keycloakConfig = {
authority: 'https://your-keycloak-domain/auth/realms/your-realm',
client_id: 'your-client-id',
redirect_uri: window.location.origin + window.location.pathname.replace(/\/$/, ''),
post_logout_redirect_uri: window.location.origin,
response_type: 'code',
scope: 'openid',
automaticSilentRenew: true,
disablePKCE: true
//...
};
return (
<DNextOidcProvider userManager={keycloakConfig} onSigninCallback={onSigninCallback}>
{/* Your application components */}
</DNextOidcProvider>
);
};
export default App;
Alternatively, if you're using a BrowserRouter or other providers, make sure DNextOidcProvider is placed appropriately:
import React from 'react';
import HomeComponent from './features/home/HomeComponent';
import { BrowserRouter } from 'react-router-dom';
import DNextOidcProvider from '@dnext-react/http/src/DNextOidcProvider';
import { onSigninCallback } from '@dnext-react/http';
function App() {
return (
<React.StrictMode>
<BrowserRouter basename="/">
<DNextOidcProvider userManager={userManager as any} onSigninCallback={onSigninCallback}>
{/* Your application components */}
</DNextOidcProvider>
</BrowserRouter>
</React.StrictMode>
);
}
3. Use the useAuth Hook¶
The dnextUseAuth hook provides access to authentication state and functions such as login and logout.
3.1. Import useAuth¶
In any component where you need to access authentication information, import the dnextUseAuth hook:
The dnextUseAuth hook provides the following properties and functions:
{
readonly settings: UserManagerSettings;
readonly events: UserManagerEvents;
clearStaleState(): Promise<void>;
removeUser(): Promise<void>;
signinPopup(args?: SigninPopupArgs): Promise<User>;
signinSilent(args?: SigninSilentArgs): Promise<User | null>;
signinRedirect(args?: SigninRedirectArgs): Promise<void>;
signinResourceOwnerCredentials(args: SigninResourceOwnerCredentialsArgs): Promise<User>;
signoutRedirect(args?: SignoutRedirectArgs): Promise<void>;
signoutPopup(args?: SignoutPopupArgs): Promise<void>;
signoutSilent(args?: SignoutSilentArgs): Promise<void>;
querySessionStatus(args?: QuerySessionStatusArgs): Promise<SessionStatus | null>;
revokeTokens(types?: RevokeTokensTypes): Promise<void>;
startSilentRenew(): void;
stopSilentRenew(): void;
}
3.2. Use the Hook in a Component¶
Here's an example of how to use dnextUseAuth in a component:
import dnextUseAuth, { hasAuthParams } from '@dnext-react/http/src/useAuth';
const Profile: React.FC = () => {
const { isLoading, isAuthenticated, user, activeNavigator, error } = dnextUseAuth();
if (!isLoading) {
return <div>Loading...</div>;
}
if (!isAuthenticated) {
return <button onClick={() => auth.signinRedirect()}>Login</button>;
}
return (
<div>
<h1>Profile</h1>
<p>Token: {token}</p>
{auth.user?.profile.map((item) => (
<div key={item.key}>
<strong>{item.key}:</strong> {item.value}
</div>
))}
<button onClick={() => logout()}>Logout</button>
</div>
);
};
export default Profile;
Explanation:
isAuthenticated: Boolean indicating if the user is authenticated.isLoading: Boolean indicating if the authentication state is still loading.user: The user object containing profile information.activeNavigator: Tracks the status of most recent signin/signout request method.error: Was there a signin or silent renew error?hasAuthParams: Check if the URL has authentication parameters.
4. Make Authenticated HTTP Requests¶
Use the httpClient instance from @dnext-react/http to make HTTP requests that automatically include the authentication token.
4.1. Import httpClient¶
In your service or component where you need to make HTTP requests:
4.2. Make Requests¶
Use httpClient to make requests as you would with Axios:
const fetchData = async () => {
try {
const response = await httpClient.get('/api/data');
console.log(response.data);
} catch (error) {
console.error('Error fetching data:', error);
}
};
Note:
- The
httpClientautomatically attaches the authentication token to theAuthorizationheader. - It also handles token refresh logic, ensuring that your requests have a valid token.
5. Protect Routes¶
If you're using React Router, you can protect routes by checking the authentication state.
5.1. Create a Protected Route Component¶
import React from 'react';
import { Route, Redirect, RouteProps } from 'react-router-dom';
import dnextUseAuth from "@dnext-react/http/src/useAuth";
interface ProtectedRouteProps extends RouteProps {
component: React.ComponentType<any>;
}
const ProtectedRoute: React.FC<ProtectedRouteProps> = ({ component: Component, ...rest }) => {
const { isAuthenticated, isLoading } = dnextUseAuth();
if (!initialized) {
return <div>Loading...</div>;
}
return (
<Route
{...rest}
render={(props) =>
isAuthenticated ? (
<Component {...props} />
) : (
login() || <Redirect to="/" />
)
}
/>
);
};
export default ProtectedRoute;
5.2. Use the Protected Route¶
In your routing configuration:
import ProtectedRoute from './ProtectedRoute';
import Dashboard from './components/Dashboard';
const AppRoutes: React.FC = () => (
<Switch>
<Route exact path="/" component={Home} />
<ProtectedRoute path="/dashboard" component={Dashboard} />
{/* Other routes */}
</Switch>
);
6. Access User Information¶
You can access additional user information from the Keycloak instance if needed.
6.1. Retrieve User Profile¶
import React from 'react';
import dnextUseAuth from "@dnext-react/http/src/useAuth";
const UserProfile: React.FC = () => {
const { initialized, isAuthenticated, user } = dnextUseAuth();
if (!initialized) {
return <div>Loading...</div>;
}
if (!isAuthenticated) {
return <div>User is not authenticated.</div>;
}
if (!profile) {
return <div>Loading profile...</div>;
}
return (
<div>
<h2>
Welcome, {profile.family_name} {profile.given_name} {profile.family_name}
</h2>
<p>preferred_username: {profile.preferred_username}</p>
<p>name: {profile.name}</p>
<p>email: {profile.email}</p>
</div>
);
};
export default UserProfile;
Explanation:
profile: The user profile object containing information such asname,email, and other attributes.initialized: Boolean indicating if the user profile has been loaded.isAuthenticated: Boolean indicating if the user is authenticated.
7. Handle Token Refresh and Errors¶
The httpClient handles token refresh automatically, but you can customize error handling if needed.
7.1. Customize Axios Interceptors¶
If you need to handle specific error scenarios, you can modify the httpClient interceptors.
// In your project, create a custom httpClient if needed
import { setAuth } from '@dnext-react/http/httpClient';
import dnextUseAuth from "@dnext-react/http/src/useAuth";
const auth = dnextUseAuth();
setAuth(auth);
8. Ensure Singleton Keycloak Instance¶
As discussed earlier, it's important that the Keycloak instance is a singleton across your application.
8.1. Use the Provided getKeycloakInstance Function¶
When you need to access the Keycloak instance directly, import getKeycloakInstance:
import { httpClient } from '@dnext-react/http/httpClient';
const httpClient = httpClient.getInstance();
httpClient: AxiosInstance
A pre-configured Axios instance for making HTTP requests.
Supported Methods:
- httpClient.get(url: string, config?: AxiosRequestConfig)
- httpClient.post(url: string, data?: any, config?: AxiosRequestConfig)
- httpClient.put(url: string, data?: any, config?: AxiosRequestConfig)
- httpClient.delete(url: string, config?: AxiosRequestConfig)
- httpClient.patch(url: string, data?: any, config?: AxiosRequestConfig)
- httpClient.head(url: string, config?: AxiosRequestConfig)
- httpClient.options(url: string, config?: AxiosRequestConfig)
9. Environment Configuration¶
For different environments (development, staging, production), you might want to manage your Keycloak configuration accordingly.
9.1. Use Environment Variables¶
Set up environment variables in your React application:
// .env.development
REACT_APP_ISSUER=https://dev-keycloak.example.com/auth
REACT_APP_KEYCLOAK_CLIENT_ID=my-client-id
// ...
// src/config/keycloakConfig.ts
const keycloakConfig = {
authority: process.env.REACT_APP_ISSUER,
client_id: process.env.REACT_APP_KEYCLOAK_CLIENT_ID,
// ...
};
export default keycloakConfig;
10. Conclusion¶
By following these steps, you can successfully integrate @dnext-react/http into your React application. The package simplifies authentication with Keycloak and provides an HTTP client that manages tokens and authentication headers automatically.
Note: Ensure that all components consuming the useAuth hook or accessing the Keycloak instance are nested within the DNextOidcProvider.