Implementing Authentication with React: In this blog will go step by to implement.
Part 1: React Authentication using Authorization Code Flow
1. Set Up Your React App
First, create a new React app if you haven’t already:
npx create-react-app my-app
cd my-app
2. Install Required Packages
Install msal
for authentication and axios
for API calls:
npm install @azure/msal-browser @azure/msal-react axios
Read Also : Updating Your Azure AD App Registration to Use v2 Endpoints
3. Configure MSAL in React
Create a new file src/authConfig.js
and add your MSAL configuration:
// src/authConfig.js
export const msalConfig = {
auth: {
clientId: 'your-client-id',
authority: 'https://login.microsoftonline.com/your-tenant-id',
redirectUri: 'http://localhost:3000',
},
cache: {
cacheLocation: 'sessionStorage', // This configures where your cache will be stored
storeAuthStateInCookie: false, // Set this to "true" if you are having issues on IE11 or Edge
}
};
export const loginRequest = {
scopes: ["User.Read"]
};
4. Set Up MSAL Provider
Wrap your application in the MsalProvider
. Modify your src/index.js
:
// src/index.js
import React from 'react';
import ReactDOM from 'react-dom';
import { PublicClientApplication } from '@azure/msal-browser';
import { MsalProvider } from '@azure/msal-react';
import { msalConfig } from './authConfig';
import App from './App';
const msalInstance = new PublicClientApplication(msalConfig);
ReactDOM.render(
<MsalProvider instance={msalInstance}>
<App />
</MsalProvider>,
document.getElementById('root')
);
Read Also : OpenID Connect with Azure : Authentication and Autorizaion
5. Create Login and Dashboard Components
Create two new components: Login.js
and Dashboard.js
.
Login.js:
// src/Login.js
import React from 'react';
import { useMsal } from '@azure/msal-react';
import { loginRequest } from './authConfig';
const Login = () => {
const { instance } = useMsal();
const handleLogin = () => {
instance.loginRedirect(loginRequest).catch(e => {
console.error(e);
});
};
return (
<div>
<h1>Login</h1>
<button onClick={handleLogin}>Sign in with Microsoft</button>
</div>
);
};
export default Login;
Dashboard.js:
// src/Dashboard.js
import React, { useEffect, useState } from 'react';
import { useMsal } from '@azure/msal-react';
import axios from 'axios';
const Dashboard = () => {
const { instance, accounts } = useMsal();
const [userName, setUserName] = useState('');
useEffect(() => {
if (accounts.length > 0) {
setUserName(accounts[0].username);
}
}, [accounts]);
const getUserInfo = async () => {
const request = {
scopes: ["User.Read"],
account: accounts[0]
};
try {
const response = await instance.acquireTokenSilent(request);
const accessToken = response.accessToken;
const result = await axios.get('https://graph.microsoft.com/v1.0/me', {
headers: {
Authorization: `Bearer ${accessToken}`
}
});
console.log(result.data);
} catch (error) {
console.error(error);
}
};
return (
<div>
<h1>Welcome, {userName}</h1>
<button onClick={getUserInfo}>Get User Info</button>
</div>
);
};
export default Dashboard;
6. Implement Routing
Set up routing to handle redirection after login. Modify src/App.js
:
// src/App.js
import React from 'react';
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
import { MsalAuthenticationTemplate, useIsAuthenticated } from '@azure/msal-react';
import Login from './Login';
import Dashboard from './Dashboard';
const App = () => {
const isAuthenticated = useIsAuthenticated();
return (
<Router>
<Switch>
<Route path="/dashboard">
{isAuthenticated ? (
<MsalAuthenticationTemplate>
<Dashboard />
</MsalAuthenticationTemplate>
) : (
<Login />
)}
</Route>
<Route path="/">
<Login />
</Route>
</Switch>
</Router>
);
};
export default App;
Read Also : Securing Your APIs: Validate Access Tokens with Azure AD in Node js
Part 2: Validate Access Tokens Using Cached JWKS Keys in Node.js
1. Install Required Packages
Install the necessary Node.js packages:
npm install axios jsonwebtoken
2. Fetch and Cache JWKS Keys
Create a new file jwksCache.js
to fetch and cache JWKS keys:
// jwksCache.js
const axios = require('axios');
const fs = require('fs');
const tenantId = 'your-tenant-id';
const jwksUri = `https://login.microsoftonline.com/${tenantId}/discovery/v2.0/keys`;
async function fetchAndCacheJWKS() {
const response = await axios.get(jwksUri);
const keys = response.data.keys;
// Optionally, you can write these keys to a file
fs.writeFileSync('jwks.json', JSON.stringify(keys));
return keys;
}
function loadJWKSFromCache() {
if (fs.existsSync('jwks.json')) {
const keys = JSON.parse(fs.readFileSync('jwks.json'));
return keys;
} else {
throw new Error('JWKS keys not found in cache');
}
}
module.exports = { fetchAndCacheJWKS, loadJWKSFromCache };
3. Validate Tokens Using Cached Keys
Create a new file validateToken.js
for token validation:
// validateToken.js
const jwt = require('jsonwebtoken');
const { loadJWKSFromCache } = require('./jwksCache');
function getKey(header, keys) {
const signingKey = keys.find(key => key.kid === header.kid);
if (signingKey) {
return signingKey.x5c[0]; // Return the X.509 certificate chain (x5c)
} else {
throw new Error('Signing key not found');
}
}
async function validateAccessToken(token) {
try {
// Load JWKS keys from cache
const keys = loadJWKSFromCache();
const decodedToken = jwt.decode(token, { complete: true });
if (!decodedToken) {
throw new Error('Invalid token');
}
const signingKey = getKey(decodedToken.header, keys);
jwt.verify(token, signingKey, {
algorithms: ['RS256'],
audience: 'your-client-id',
issuer: `https://login.microsoftonline.com/${tenantId}/v2.0`,
}, (err, decoded) => {
if (err) {
throw err;
}
console.log('Token is valid', decoded);
});
} catch (error) {
console.error('Token validation failed', error);
}
}
// Example usage:
const accessToken = 'your-access-token';
validateAccessToken(accessToken);
Conclusion: Implementing Authentication with React
In this guide, we’ve covered how to set up React to use MSAL for authentication via the authorization code flow and handle post-authentication redirection. We also covered how to validate access tokens using cached JWKS keys in Node.js to avoid latency caused by HTTP calls. This setup ensures a smooth and secure authentication experience for users.
Hey Tech Enthusiasts!
I’m Avinash, a passionate tech blogger with over 13+ years of experience in the trenches of software engineering.
You could say I’ve worn many hats in my journey – from full-stack developer crafting beautiful and functional applications to Solution Architect, designing the architecture for complex systems.
Over the years, I’ve delved into a vast arsenal of languages and tools, including the Generative AI (LLMs, LLM-Proxy, Observability, Prompt Engineering), .NET family (.NET, .NET Core), PHP, Rust, Python, the JavaScript frameworks (Angular, React, Node.js), and databases like MySQL, SQL Server, MongoDB.
As the cloud revolutionized our world, I’ve become well-versed in both Azure and GCP platforms, wielding Docker for containerization and CI/CD pipelines to streamline development workflows.
Here on my blog, I aim to share the knowledge I’ve accumulated and the lessons I’ve learned along the way. Whether you’re a seasoned developer or just starting your coding adventure, I want to provide you with insightful, practical articles that tackle real-world tech challenges.
Get ready to explore the latest advancements, delve into programming concepts, and discover efficient solutions to your development dilemmas. So, buckle up, tech enthusiasts – let’s embark on this exciting journey together!