├── .babelrc ├── .gitignore ├── .vscode └── settings.json ├── LICENSE ├── README.md ├── lib └── msal-b2c-react.js ├── package-lock.json ├── package.json └── src └── msal-b2c-react.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["env", "react-app"] 3 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.tabSize": 4 3 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 James Randall 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # README 2 | 3 | Azure AD B2C is a identity provider covering social and enterprise logins. 4 | 5 | The Microsoft Authentication library (MSAL) is JavaScript library to authenticate enterprise users using Microsoft Azure Active Directory (AAD), Microsoft account users (MSA), users using social identity providers like Facebook, Google, LinkedIn etc. and get access to Microsoft Cloud or Microsoft Graph. 6 | 7 | This module is React wrapper over MSAL for Azure AD B2C. It fully supports active SSO sessions. 8 | 9 | ## Installation 10 | 11 | If you are using npm: 12 | 13 | npm install @kdpw/msal-b2c-react --save 14 | 15 | Or if you are using yarn: 16 | 17 | yarn add @kdpw/msal-b2c-react 18 | 19 | ## Initializing the Library 20 | 21 | You'll first need to load the module and pass some configuration to the library. Normally this would go in your index.js file: 22 | 23 | import authentication from '@kdpw/msal-b2c-react'; 24 | 25 | authentication.initialize({ 26 | // you can user your b2clogin.com domain here, setting is optional, will default to this 27 | instance: 'https://login.microsoftonline.com/tfp/', 28 | // your B2C tenant, you can also user tenants GUID here 29 | tenant: 'myb2ctenant.onmicrosoft.com', 30 | // the policy to use to sign in, can also be a sign up or sign in policy 31 | signInPolicy: 'mysigninpolicy', 32 | // the policy to use for password reset 33 | resetPolicy: 'mypasswordresetpolicy', 34 | // the the B2C application you want to authenticate with (that's just a random GUID - get yours from the portal) 35 | applicationId: '75ee2b43-ad2c-4366-9b8f-84b7d19d776e', 36 | // where MSAL will store state - localStorage or sessionStorage 37 | cacheLocation: 'sessionStorage', 38 | // the scopes you want included in the access token 39 | scopes: ['https://myb2ctenant.onmicrosoft.com/management/admin'], 40 | // optional, the redirect URI - if not specified MSAL will pick up the location from window.href 41 | redirectUri: 'http://localhost:3000', 42 | // optional, the URI to redirect to after logout 43 | postLogoutRedirectUri: 'http://myapp.com', 44 | // optional, default to true, set to false if you change instance 45 | validateAuthority: false, 46 | // optional, default to false, set to true if you only want to acquire token silently and avoid redirections to login page 47 | silentLoginOnly: false 48 | }); 49 | 50 | ## Authenticating When The App Starts 51 | 52 | If you want to set things up so that a user is authenticated as soon as they hit your app (for example if you've got a link to an app from a landing page) then, in index.js, wrap the lines of code that launch the React app with the _authentication.run_ function: 53 | 54 | authentication.run(() => { 55 | ReactDOM.render(, document.getElementById('root')); 56 | registerServiceWorker(); 57 | }); 58 | 59 | ## Triggering Authentication Based on Components Mounting (and routing) 60 | 61 | If you want to set things up so that a user is authenticated as they visit a part of the application that requires authentication then the appropriate components can be wrapped inside higher order components that will handle the authentication process. This is done using the _authentication.required_ function, normally in conjunction with a router. The example below shows this using the popular react-router: 62 | 63 | import React, { Component } from 'react'; 64 | import authentication from '@kdpw/msal-b2c-react' 65 | import { BrowserRouter as Router, Route, Switch } from "react-router-dom"; 66 | import HomePage from './Homepage' 67 | import MembersArea from './MembersArea' 68 | 69 | class App extends Component { 70 | render() { 71 | return ( 72 | 73 | 74 | 75 | 76 | 77 | 78 | ); 79 | } 80 | } 81 | 82 | ## Getting the Id Token 83 | 84 | Simply call the method _getIdToken_: 85 | 86 | import authentication from '@kdpw/msal-b2c-react' 87 | 88 | // ... 89 | 90 | const id_token = authentication.getIdToken(); 91 | 92 | ## Getting the Access Token 93 | 94 | Simply call the method _getAccessToken_: 95 | 96 | import authentication from '@kdpw/msal-b2c-react' 97 | 98 | // ... 99 | 100 | const access_token = authentication.getAccessToken(); 101 | 102 | ## Getting the User Name 103 | 104 | Simply call the method _getUserName_: 105 | 106 | import authentication from '@kdpw/msal-b2c-react' 107 | 108 | // ... 109 | 110 | const userName = authentication.getUserName(); 111 | 112 | ## Signing Out 113 | 114 | To sign out: 115 | 116 | import authentication from '@kdpw/msal-b2c-react' 117 | 118 | // ... 119 | 120 | authentication.signOut(); 121 | 122 | ## Thanks 123 | 124 | To build this I made fork of [react-azure-adb2c](https://github.com/JamesRandall/react-azure-adb2c) module. Thanks! 125 | -------------------------------------------------------------------------------- /lib/msal-b2c-react.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | 7 | var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); 8 | 9 | var _msal = require('msal'); 10 | 11 | var Msal = _interopRequireWildcard(_msal); 12 | 13 | var _react = require('react'); 14 | 15 | var _react2 = _interopRequireDefault(_react); 16 | 17 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 18 | 19 | function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } 20 | 21 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } 22 | 23 | function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } 24 | 25 | function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } // note on window.msal usage. There is little point holding the object constructed by new Msal.UserAgentApplication 26 | // as the constructor for this class will make callbacks to the acquireToken function and these occur before 27 | // any local assignment can take place. Not nice but its how it works. 28 | 29 | 30 | var logger = new Msal.Logger(loggerCallback, { 31 | level: Msal.LogLevel.Warning 32 | }); 33 | var state = { 34 | noScopes: false, 35 | launchApp: null, 36 | idToken: null, 37 | accessToken: null, 38 | userName: "" 39 | }; 40 | var appConfig = { 41 | // optional, will default to 'https://login.microsoftonline.com/tfp/' 42 | instance: null, 43 | // your B2C tenant 44 | tenant: null, 45 | // the policy to use to sign in, can also be a sign up or sign in policy 46 | signInPolicy: null, 47 | // the policy to use for password reset 48 | resetPolicy: null, 49 | // the the B2C application you want to authenticate with 50 | applicationId: null, 51 | // where MSAL will store state - localStorage or sessionStorage 52 | cacheLocation: null, 53 | // optional, the scopes you want included in the access token 54 | scopes: [], 55 | // optional, the redirect URI - if not specified MSAL will pick up the location from window.href 56 | redirectUri: null, 57 | // optional, the URI to redirect to after logout 58 | postLogoutRedirectUri: null, 59 | // optional, default to true, set to false if you change instance 60 | validateAuthority: null, 61 | // optional, default to false, set to true if you want to acquire token silently and avoid redirections to login page 62 | silentLoginOnly: false 63 | }; 64 | 65 | function loggerCallback(logLevel, message, piiLoggingEnabled) { 66 | console.log(message); 67 | } 68 | 69 | function authCallback(errorDesc, token, error, tokenType) { 70 | if (errorDesc && errorDesc.indexOf('AADB2C90118') > -1) { 71 | redirect(); 72 | } else if (errorDesc) { 73 | console.log(error + ':' + errorDesc); 74 | } else {} 75 | } 76 | 77 | function redirect() { 78 | var localMsalApp = window.msal; 79 | var instance = appConfig.instance ? appConfig.instance : 'https://login.microsoftonline.com/tfp/'; 80 | var authority = '' + instance + appConfig.tenant + '/' + appConfig.resetPolicy; 81 | localMsalApp.authority = authority; 82 | loginAndAcquireToken(); 83 | } 84 | 85 | function loginAndAcquireToken(successCallback) { 86 | var localMsalApp = window.msal; 87 | var user = localMsalApp.getUser(appConfig.scopes); 88 | 89 | if (!user) { 90 | 91 | // user is not logged in 92 | if (state.noScopes) { 93 | // no need of access token 94 | if (appConfig.silentLoginOnly) { 95 | // on silent mode we call error app 96 | if (state.errorApp) state.errorApp(); 97 | } else 98 | // just redirect to login page 99 | localMsalApp.loginRedirect(appConfig.scopes); 100 | } else { 101 | // try to get token from SSO session 102 | localMsalApp.acquireTokenSilent(appConfig.scopes, null, null, "&login_hint&domain_hint=organizations").then(function (accessToken) { 103 | state.accessToken = accessToken; 104 | user = localMsalApp.getUser(appConfig.scopes); 105 | state.idToken = user.idToken; 106 | state.userName = user.name; 107 | if (state.launchApp) { 108 | state.launchApp(); 109 | } 110 | if (successCallback) { 111 | successCallback(); 112 | } 113 | }, function (error) { 114 | if (error) { 115 | if (appConfig.silentLoginOnly) state.errorApp();else localMsalApp.loginRedirect(appConfig.scopes); 116 | } 117 | }); 118 | } 119 | } else { 120 | 121 | // the user is already logged in 122 | state.idToken = user.idToken; 123 | state.userName = user.name; 124 | if (state.noScopes) { 125 | // no need of access token, just launch the app 126 | if (state.launchApp) { 127 | state.launchApp(); 128 | } 129 | if (successCallback) { 130 | successCallback(); 131 | } 132 | } else { 133 | // get access token 134 | localMsalApp.acquireTokenSilent(appConfig.scopes).then(function (accessToken) { 135 | state.accessToken = accessToken; 136 | if (state.launchApp) { 137 | state.launchApp(); 138 | } 139 | if (successCallback) { 140 | successCallback(); 141 | } 142 | }, function (error) { 143 | if (error) { 144 | localMsalApp.acquireTokenRedirect(appConfig.scopes); 145 | } 146 | }); 147 | } 148 | } 149 | } 150 | 151 | var authentication = { 152 | initialize: function initialize(config) { 153 | appConfig = config; 154 | var instance = config.instance ? config.instance : 'https://login.microsoftonline.com/tfp/'; 155 | var authority = '' + instance + config.tenant + '/' + config.signInPolicy; 156 | var validateAuthority = config.validateAuthority != null ? config.validateAuthority : true; 157 | var scopes = config.scopes; 158 | if (!scopes || scopes.length === 0) { 159 | console.log('To obtain access tokens you must specify one or more scopes. See https://docs.microsoft.com/en-us/azure/active-directory-b2c/active-directory-b2c-access-tokens'); 160 | state.noScopes = true; 161 | } 162 | state.scopes = scopes; 163 | 164 | new Msal.UserAgentApplication(config.applicationId, authority, authCallback, { 165 | logger: logger, 166 | cacheLocation: config.cacheLocation, 167 | postLogoutRedirectUri: config.postLogoutRedirectUri, 168 | redirectUri: config.redirectUri, 169 | validateAuthority: validateAuthority 170 | }); 171 | }, 172 | run: function run(launchApp, errorApp) { 173 | state.launchApp = launchApp; 174 | if (errorApp) state.errorApp = errorApp; 175 | if (!window.msal.isCallback(window.location.hash) && window.parent === window && !window.opener) { 176 | loginAndAcquireToken(); 177 | } 178 | }, 179 | required: function required(WrappedComponent, renderLoading) { 180 | return function (_React$Component) { 181 | _inherits(_class, _React$Component); 182 | 183 | function _class(props) { 184 | _classCallCheck(this, _class); 185 | 186 | var _this = _possibleConstructorReturn(this, (_class.__proto__ || Object.getPrototypeOf(_class)).call(this, props)); 187 | 188 | _this.state = { 189 | signedIn: false, 190 | error: null 191 | }; 192 | return _this; 193 | } 194 | 195 | _createClass(_class, [{ 196 | key: 'componentWillMount', 197 | value: function componentWillMount() { 198 | var _this2 = this; 199 | 200 | loginAndAcquireToken(function () { 201 | _this2.setState(Object.assign({}, _this2.state, { 202 | signedIn: true 203 | })); 204 | }); 205 | } 206 | }, { 207 | key: 'render', 208 | value: function render() { 209 | if (this.state.signedIn) { 210 | return _react2.default.createElement(WrappedComponent, this.props); 211 | }; 212 | return typeof renderLoading === 'function' ? renderLoading() : null; 213 | } 214 | }]); 215 | 216 | return _class; 217 | }(_react2.default.Component); 218 | }, 219 | signOut: function signOut() { 220 | window.msal.logout(); 221 | }, 222 | getIdToken: function getIdToken() { 223 | return state.idToken; 224 | }, 225 | getAccessToken: function getAccessToken() { 226 | return state.accessToken; 227 | }, 228 | getUserName: function getUserName() { 229 | return state.userName; 230 | } 231 | }; 232 | 233 | exports.default = authentication; -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@kdpw/msal-b2c-react", 3 | "version": "0.0.3", 4 | "description": "React wrapper over MS Authentication library for Azure AD B2C", 5 | "main": "lib/msal-b2c-react.js", 6 | "scripts": { 7 | "compile": "cross-env NODE_ENV=production babel src --out-dir lib", 8 | "prepublish": "npm run compile" 9 | }, 10 | "repository": { 11 | "type": "git", 12 | "url": "git+https://github.com/leszekczajka/msal-b2c-react.git" 13 | }, 14 | "keywords": [ 15 | "react", 16 | "js", 17 | "AAD", 18 | "B2C", 19 | "oauth", 20 | "azure", 21 | "msal" 22 | ], 23 | "author": "James Randall", 24 | "contributors": [ 25 | "Leszek Czajka " 26 | ], 27 | "license": "MIT", 28 | "bugs": { 29 | "url": "https://github.com/leszekczajka/msal-b2c-react/issues" 30 | }, 31 | "homepage": "https://github.com/leszekczajka/msal-b2c-react#readme", 32 | "dependencies": { 33 | "msal": "^0.2.3" 34 | }, 35 | "peerDependencies": { 36 | "react": "^15.0.0 || ^16.0.0" 37 | }, 38 | "devDependencies": { 39 | "babel-cli": "^6.26.0", 40 | "babel-core": "6.24.1", 41 | "babel-eslint": "^8.0.3", 42 | "babel-jest": "20.0.3", 43 | "babel-loader": "7.0.0", 44 | "babel-plugin-import": "^1.2.1", 45 | "babel-polyfill": "^6.23.0", 46 | "babel-preset-env": "^1.6.1", 47 | "babel-runtime": "6.23.0", 48 | "babel-preset-react-app": "^3.0.0", 49 | "cross-env": "^5.1.4", 50 | "eslint": "^4.12.1", 51 | "eslint-config-airbnb": "^16.1.0", 52 | "eslint-config-defaults": "^9.0.0", 53 | "eslint-plugin-import": "^2.8.0", 54 | "eslint-plugin-jsx-a11y": "^6.0.2", 55 | "eslint-plugin-react": "^7.5.1" 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/msal-b2c-react.js: -------------------------------------------------------------------------------- 1 | // note on window.msal usage. There is little point holding the object constructed by new Msal.UserAgentApplication 2 | // as the constructor for this class will make callbacks to the acquireToken function and these occur before 3 | // any local assignment can take place. Not nice but its how it works. 4 | import * as Msal from 'msal'; 5 | import React from 'react'; 6 | 7 | const logger = new Msal.Logger(loggerCallback, { 8 | level: Msal.LogLevel.Warning 9 | }); 10 | const state = { 11 | noScopes: false, 12 | launchApp: null, 13 | idToken: null, 14 | accessToken: null, 15 | userName: "" 16 | } 17 | var appConfig = { 18 | // optional, will default to 'https://login.microsoftonline.com/tfp/' 19 | instance: null, 20 | // your B2C tenant 21 | tenant: null, 22 | // the policy to use to sign in, can also be a sign up or sign in policy 23 | signInPolicy: null, 24 | // the policy to use for password reset 25 | resetPolicy: null, 26 | // the the B2C application you want to authenticate with 27 | applicationId: null, 28 | // where MSAL will store state - localStorage or sessionStorage 29 | cacheLocation: null, 30 | // optional, the scopes you want included in the access token 31 | scopes: [], 32 | // optional, the redirect URI - if not specified MSAL will pick up the location from window.href 33 | redirectUri: null, 34 | // optional, the URI to redirect to after logout 35 | postLogoutRedirectUri: null, 36 | // optional, default to true, set to false if you change instance 37 | validateAuthority: null, 38 | // optional, default to false, set to true if you want to acquire token silently and avoid redirections to login page 39 | silentLoginOnly: false 40 | }; 41 | 42 | function loggerCallback(logLevel, message, piiLoggingEnabled) { 43 | console.log(message); 44 | } 45 | 46 | function authCallback(errorDesc, token, error, tokenType) { 47 | if (errorDesc && errorDesc.indexOf('AADB2C90118') > -1) { 48 | redirect(); 49 | } else if (errorDesc) { 50 | console.log(error + ':' + errorDesc); 51 | } else {} 52 | } 53 | 54 | function redirect() { 55 | const localMsalApp = window.msal; 56 | const instance = appConfig.instance ? appConfig.instance : 'https://login.microsoftonline.com/tfp/'; 57 | const authority = `${instance}${appConfig.tenant}/${appConfig.resetPolicy}`; 58 | localMsalApp.authority = authority; 59 | loginAndAcquireToken(); 60 | } 61 | 62 | function loginAndAcquireToken(successCallback) { 63 | const localMsalApp = window.msal; 64 | let user = localMsalApp.getUser(appConfig.scopes); 65 | 66 | if (!user) { 67 | 68 | // user is not logged in 69 | if (state.noScopes) { 70 | // no need of access token 71 | if (appConfig.silentLoginOnly) { 72 | // on silent mode we call error app 73 | if (state.errorApp) 74 | state.errorApp(); 75 | } else 76 | // just redirect to login page 77 | localMsalApp.loginRedirect(appConfig.scopes); 78 | } else { 79 | // try to get token from SSO session 80 | localMsalApp.acquireTokenSilent(appConfig.scopes, null, null, "&login_hint&domain_hint=organizations").then(accessToken => { 81 | state.accessToken = accessToken; 82 | user = localMsalApp.getUser(appConfig.scopes); 83 | state.idToken = user.idToken; 84 | state.userName = user.name; 85 | if (state.launchApp) { 86 | state.launchApp(); 87 | } 88 | if (successCallback) { 89 | successCallback(); 90 | } 91 | }, error => { 92 | if (error) { 93 | if (appConfig.silentLoginOnly) 94 | state.errorApp(); 95 | else 96 | localMsalApp.loginRedirect(appConfig.scopes); 97 | } 98 | }); 99 | } 100 | 101 | } else { 102 | 103 | // the user is already logged in 104 | state.idToken = user.idToken; 105 | state.userName = user.name; 106 | if (state.noScopes) { 107 | // no need of access token, just launch the app 108 | if (state.launchApp) { 109 | state.launchApp(); 110 | } 111 | if (successCallback) { 112 | successCallback(); 113 | } 114 | } else { 115 | // get access token 116 | localMsalApp.acquireTokenSilent(appConfig.scopes).then(accessToken => { 117 | state.accessToken = accessToken; 118 | if (state.launchApp) { 119 | state.launchApp(); 120 | } 121 | if (successCallback) { 122 | successCallback(); 123 | } 124 | }, error => { 125 | if (error) { 126 | localMsalApp.acquireTokenRedirect(appConfig.scopes); 127 | } 128 | }); 129 | } 130 | 131 | } 132 | 133 | } 134 | 135 | const authentication = { 136 | initialize: (config) => { 137 | appConfig = config; 138 | const instance = config.instance ? config.instance : 'https://login.microsoftonline.com/tfp/'; 139 | const authority = `${instance}${config.tenant}/${config.signInPolicy}`; 140 | const validateAuthority = (config.validateAuthority != null) ? config.validateAuthority : true; 141 | let scopes = config.scopes; 142 | if (!scopes || scopes.length === 0) { 143 | console.log('To obtain access tokens you must specify one or more scopes. See https://docs.microsoft.com/en-us/azure/active-directory-b2c/active-directory-b2c-access-tokens'); 144 | state.noScopes = true; 145 | } 146 | state.scopes = scopes; 147 | 148 | new Msal.UserAgentApplication( 149 | config.applicationId, 150 | authority, 151 | authCallback, { 152 | logger: logger, 153 | cacheLocation: config.cacheLocation, 154 | postLogoutRedirectUri: config.postLogoutRedirectUri, 155 | redirectUri: config.redirectUri, 156 | validateAuthority: validateAuthority 157 | } 158 | ); 159 | }, 160 | run: (launchApp, errorApp) => { 161 | state.launchApp = launchApp 162 | if (errorApp) 163 | state.errorApp = errorApp; 164 | if (!window.msal.isCallback(window.location.hash) && window.parent === window && !window.opener) { 165 | loginAndAcquireToken(); 166 | } 167 | }, 168 | required: (WrappedComponent, renderLoading) => { 169 | return class extends React.Component { 170 | constructor(props) { 171 | super(props); 172 | this.state = { 173 | signedIn: false, 174 | error: null, 175 | }; 176 | } 177 | 178 | componentWillMount() { 179 | loginAndAcquireToken(() => { 180 | this.setState({ 181 | ...this.state, 182 | signedIn: true 183 | }); 184 | }); 185 | }; 186 | 187 | render() { 188 | if (this.state.signedIn) { 189 | return ( < WrappedComponent { 190 | ...this.props 191 | } 192 | />); 193 | }; 194 | return typeof renderLoading === 'function' ? renderLoading() : null; 195 | }; 196 | }; 197 | }, 198 | signOut: () => { 199 | window.msal.logout() 200 | }, 201 | getIdToken: () => { 202 | return state.idToken; 203 | }, 204 | getAccessToken: () => { 205 | return state.accessToken; 206 | }, 207 | getUserName: () => { 208 | return state.userName; 209 | } 210 | } 211 | 212 | export default authentication; --------------------------------------------------------------------------------