@calvear/react-azure-msal-security

React library (MSAL wrapper) for Azure Active Directory authentication.

Usage no npm install needed!

<script type="module">
  import calvearReactAzureMsalSecurity from 'https://cdn.skypack.dev/@calvear/react-azure-msal-security';
</script>

README

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 🎉

✅ Centralized and synchronized session state handling for any authentication event.

✅ Automatic and manual login hooks.

✅ Logout, state and token acquisition hooks.

✅ Refresh token route handler.

✅ User specific profile info and avatar hooks, using Microsoft Graph.

⚠️ Easy to use! but a little hard to customize, i.e. user graph info.

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:

  • https://localhost:3000/
  • https://localhost:3000/auth

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.


⌨ by Alvear Candia, Cristopher Alejandro