React Azure MSAL Security
Azure Active Directory security module using MSAL
React library for application security (using MSAL) that eases application protection with Azure session JWT. Exposes multiples hooks for login, logout and secure components.
📋
Structure ├── README.md
├── LICENCE.md
├── CHANGELOG.md
├── .vscode/ # vscode shared development config
├── src/
│ ├── security/
│ │ ├── config/
│ │ │ ├── aad.config.js # MSAL config initialization
│ │ │ └── aad.types.js # AAD and Ms Graph constants
│ │ ├── services/
│ │ │ ├── aad-graph.service.js # basic graph service for user info and avatar
│ │ │ └── aad.service.js # service for handle login, sso and token acquisition
│ │ ├── auth.hook.js # module hooks
│ │ ├── cache.util.js # util for persist graph info
│ │ └── observer.util.js # observer pattern handler
│ └── index.js
├── package.json
├── jsconfig.js
├── .babelrc
├── .eslintrc.json
└── .prettierrc.json
Files | Description |
---|---|
aad.config.js |
contains context config |
aad.types.js |
contains MSAL anf Microsoft Graph constants |
aad.service.js |
main service. Handles MSAL context, session state, login, logout and token acquisition |
aad-graph.service.js |
handles Microsoft Graph calls, like user detailed info and profile avatar |
auth.hooks.js |
exposed hooks for login, logout and secure components |
index.js |
exports router, hooks and routes handler/service |
🎉
Features
📖
How To Configure First, you should register a new Azure Active Directory Application in Azure Portal.
In Authentication section add a new platform, selecting Single-Page Application (SPA) and setting up Redirect URIs only, with host (base URL) and token auth URL, for example, for dev:
Also, in this section, enable Access tokens and ID tokens in Implicit grant sub-section.
Finally, you should configure permissions in API permissions section, with the minimum permission User.Read, although ideally profile and openid for correct token acquisition.
💡
How To Use This module, exposes many hooks for handle login, logout and secure React components.
App configuration
In your App.jsx or App.router.jsx you should initialize the authentication service.
import { AuthenticationService } from '@calvear/react-azure-msal-security';
// MSAL config.
const authConfig = {
clientId: '2a85c521-02fc-4796-8ecc-eaa13eee2e7b', // registered app id from azure
tenantId: 'ba3947ca-abb7-402e-b1d1-c9284608f497', // maybe common, organizations or consumers also
loginActionRedirect: '/',
logoutActionRedirect: null,
tokenRefreshUri: '/auth', // should exists a blank route in your app
tokenRenewalOffset: 120,
navigateToRequestAfterLogin: true,
};
// initializes Microsoft Active Directory authentication service.
AuthenticationService.init(authConfig);
// main react component
export default () => {
return (
<div>
<h1>Welcome to My App</h1>
</div>
);
};
Parameters | Description |
---|---|
[config] |
settings |
[config.tenantId] |
organization Azure client id |
[config.clientId] |
application Azure client id |
[config.loginActionRedirect] |
(default: '/') - redirect path after login |
[config.logoutActionRedirect] |
(default: null) - redirect path after logout |
[config.tokenRefreshUri] |
(default: '/auth') - path for renew auth token |
[config.tokenRenewalOffset] |
(default: 120) token renewal interval |
[config.navigateToRequestAfterLogin] |
(default: true) - if app redirects to previous path after login |
[config.infoCacheDurationInDays] |
(default: 1) - days for store user info cached |
[config.photoCacheDurationInDays] |
(default: 3) - days for store user photo cached |
[disabled] |
(default: false) - if authentication is disabled globally |
For tenantId also see MSAL Client Config
Token acquisition and blank page/route
For a correct authentication and token renewal operation you should define a blank page or route in your application. This route will be used as iframe for retrieve or renew the token on authentication.
For example, if you're using react-spa-routerizer
// routes.js
export default [
...,
// blank html page for load authentication iframe to refresh the token,
// also, you should set tokenRefreshUri as '/auth' route.
{
key: 'auth-page',
title: 'Authenticating',
path: '/auth',
Child: () => null
},
...
];
☑️ Check Authentication State
import { useAuthenticationState } from '@calvear/react-azure-msal-security';
// react component
export default () => {
const { authenticated, authenticating, error } = useAuthenticationState();
return (
<div>
<h1>User is authenticated?: {authenticated ? 'yeah' : 'no'}</h1>
</div>
);
};
Returning Modules | Description |
---|---|
state |
object with authentication state |
state.authenticated |
if user is authenticated |
state.authenticating |
if service is authenticating |
state.error |
error object |
☑️ Automatic Login
import { useAuthentication } from '@calvear/react-azure-msal-security';
// react component
export default () => {
const { authenticated, authenticating, error } = useAuthentication();
if (authenticating) return <div>Authenticating...</div>;
if (!authenticated) return <div>403: Not Authorized - {error.message}</div>;
return (
<div>
<h1>Welcome to My App</h1>
</div>
);
};
Returning Modules | Description |
---|---|
state |
object with authentication state |
state.authenticated |
if user is authenticated |
state.authenticating |
if service is authenticating |
state.error |
error object |
Parameters | Description |
---|---|
[config] |
settings |
[config.loginType] |
(default: loginRedirect) - loginRedirect or loginPopup |
☑️ Manual Login
import { Redirect } from 'react-router-dom';
import { useAuthenticationState, useLogin } from '@calvear/react-azure-msal-security';
// react component
export default () => {
const login = useLogin();
const { authenticated, authenticating, error } = useAuthenticationState();
if(authenticating)
return <div>Authenticating...</div>;
if(!authenticated)
return <div>403: Not Authorized - {error.message}</div>;
if(authenticated)
return <Redirect to='/home'>;
return (
<div>
<button onClick={login}>Log In</button>
</div>
);
}
Returning Modules | Description |
---|---|
login |
(login) function for trigger login/authentication |
Parameters | Description |
---|---|
[loginType] |
(default: loginRedirect) loginRedirect or loginPopup |
☑️ Logout
import { useLogout } from '@calvear/react-azure-msal-security';
// react component
export default () => {
const logout = useLogout();
return (
<div>
<button onClick={logout}>Log Out</button>
</div>
);
};
Returning Modules | Description |
---|---|
logout |
function for logout |
☑️ Acquire Token
You can acquire a JWT access token for API securing.
import { useState, useEffect } from 'react';
import { useAcquireToken } from '@calvear/react-azure-msal-security';
// react component
export default () => {
const [token, setToken] = useState();
const { authenticated } = useAuthentication();
// use it only if authentication was succeeded
const acquireToken = useAcquireToken();
useEffect(() => {
if (authenticated) {
acquireToken().then((tkn) => setToken(tkn));
}
}, [authenticated]);
return (
<div>
<h1>Welcome to My App</h1>
</div>
);
};
Returning Modules | Description |
---|---|
acquireToken |
async function for acquire an access token |
Parameters | Description |
---|---|
[forceTokenRefresh] |
(default: false) - forces to renew token from active directory. |
☑️ Graph Info
You can retrieves user account detailed info and profile avatar from Microsoft Graph api with hooks.
import { useAccountInfo } from '@calvear/react-azure-msal-security';
// react component
export default () => {
const { loading, info, error } = useAccountInfo();
if (loading) return <div>Loading User Info...</div>;
if (error) return <div>User info cannot be loaded: {error.message}</div>;
return (
<div>
<h1>User Info</h1>
<h3>Name: {info.displayName}</h3>
</div>
);
};
Returning Modules | Description |
---|---|
state |
object with info state |
state.loading |
if info is loading |
state.info |
account info |
state.error |
error object |
import { useAccountAvatar } from '@calvear/react-azure-msal-security';
// react component
export default () => {
const { loading, avatar, error } = useAccountAvatar();
if (loading) return <div>Loading User Avatar...</div>;
if (error) return <div>User avatar cannot be loaded: {error.message}</div>;
return (
<div>
<img alt="user-avatar" src={avatar} />
</div>
);
};
Returning Modules | Description |
---|---|
state |
object with avatar state |
state.loading |
if avatar is loading |
state.avatar |
account avatar in base64 |
state.error |
error object |
Parameters | Description |
---|---|
[size] |
(default: 648x648) avatar sizes. Values maybe 48x48, 64x64, 96x96, 120x120, 240x240, 360x360, 432x432, 504x504 or 648x648 |
🧿
Linting Project uses ESLint, for code formatting and code styling normalizing.
- eslint: JavaScript and React linter with Airbnb React base config and some other additions.
- prettier: optional Prettier config.
For correct interpretation of linters, is recommended to use Visual Studio Code as IDE and install the plugins in .vscode folder at 'extensions.json', as well as use the config provided in 'settings.json'
📄
Changelog For last changes see CHANGELOG.md file for details.
🛠️
Built with - React - the most fabulous JavaScript framework.
- MSAL - Microsoft Authentication Library for JavaScript.
- axios - Promise based HTTP client.
📄
License This project is licensed under the MIT License - see LICENSE.md file for details.