Skip to content

Repository files navigation

Multiple Authentication React

This project provides a multiple authentication process using React. So, you can use multiple methods to user autheticate inside your application, besides, the structure makes easy the development of others methods likes GitHub and Facebook.

Using it, you'll find these providers:

  1. INTERN - Using your own authentication api;
  2. AZURE - Using Microsoft authentication;
  3. GOOGLE - Using Google authentication;

Auth Hook

Inside Login and others pages, you can access the signIn and signOut methods, and get the user data or verify if it's logged. In this example, I'm using it on login page with signIn method when button clicked, and checking if it is authenticated using useEffect hook, like that:

exportfunctionLogin(){
const { isAuthenticated, signIn } =useAuth();
useEffect(() => {
setIsLoading(false);
if(isAuthenticated){
navigate('/home');
}
}, [isAuthenticated])
...
functionhandleSignInAzure() {
signIn('AZURE');
}
functionhandleSignInIntern(){
if(!authUser.email) {
alert('E-mail não informado')
return;
};
if(!authUser.password) {
alert('Senha não informada');
return;
}
signIn('INTERN', authUser);
}
functionhandleSignInGoogle(){
signIn('GOOGLE');
}
return (
...
)

The Context code used by useAuth is AuthContext.tsx


Environment variables

Normally, the external authetications likes Microsoft and Google, it needs a key called clientId, because of that, you'll need to set your own key on .env file.

// .env.exampleVITE_AZURE_CLIENT_ID=VITE_GOOGLE_CLIENT_ID=VITE_LOGIN_PAGE=http://localhost:3000

Follow these tutorials to get the clientId keys:


Auth Config

Inside the services folder, you'll find some config files like azure.config.ts, and google.config.ts; those files contains some basics informations to use the services, and it'll be using the clientId keys that you got on previous topic.

// azure.config.tsexportconstmsalConfig={auth: {clientId: import.meta.env.VITE_AZURE_CLIENT_ID,redirectUri: import.meta.env.VITE_LOGIN_PAGE,authority: "https://login.microsoftonline.com/common",},cache: {cacheLocation: 'sessionStorage',storeAuthStateInCookie: false,},}asMsalConfig;exportconstloginRequest={scopes: ['user.read'],}
// google.config.tsexportconstgoogleConfig={clientId: import.meta.env.VITE_GOOGLE_CLIENT_ID,uxMode: 'redirect',redirectUri: import.meta.env.VITE_LOGIN_PAGE,scopes: 'profile email openid',cookiePolicy: 'single_host_origin'}asgapi.auth2.ClientConfig;

Auth Services

All services implements the IAuth interface, so you can use these methods:

export interfaceIAuth{type: AuthMethodKey;
signIn: (authUser?: AuthUser)=>Promise<User|void>;
signOut: ()=>Promise<void>;
isAuthenticated: ()=>Promise<boolean>;getUser: ()=>Promise<User|undefined>;}

Azure

Check code!

import{AuthenticationResult,IPublicClientApplication,PublicClientApplication}from'@azure/msal-browser';import{Client}from'@microsoft/microsoft-graph-client';import{loginRequest,msalConfig}from'../../services/azure.config';import{User,AuthMethodKey}from'./auth.model';import{IAuth}from'./IAuth';exportclassAuthAzureimplementsIAuth{publictype: AuthMethodKey='AZURE';privateinstance: PublicClientApplication;constructor(){this.instance=newPublicClientApplication(msalConfig);console.log('starting auth azure');}publicsignIn=async()=>{console.log('signIn azure');awaitthis.instance.handleRedirectPromise().then(()=>{this.handleLogin(this.instance);});};publicsignOut=async()=>{console.log('signOut azure');awaitthis.instance.handleRedirectPromise().then(()=>{this.handleLogout(this.instance);});};publicisAuthenticated=async()=>{returnawaitthis.instance.handleRedirectPromise().then(x=>{constaccounts=this.instance.getAllAccounts();returnaccounts.length>0;});};publicgetUser=async()=>{constuserStorage=localStorage.getItem('@Auth.user');if(userStorage!==null){returnJSON.parse(userStorage)asUser;}constaccounts=this.instance.getAllAccounts();if(accounts.length===0){returnundefined;}constrequest={
...loginRequest,account: accounts[0]};// Silently acquires an access token which is then attached to a request for Microsoft Graph dataconstuserAzure=awaitthis.instance.acquireTokenSilent(request).then((response: AuthenticationResult)=>{returnthis.getUserDetails(response.accessToken);});if(userAzure){constuser={email: userAzure.userPrincipalName,username: userAzure.displayName}asUser;localStorage.setItem('@Auth.user',JSON.stringify(user));returnuser;}returnundefined;}privategetAuthenticatedClient=(accessToken: string)=>{constclient=Client.init({authProvider: (done)=>{done(null,accessToken);}});returnclient;}privategetUserDetails=async(accessToken: string)=>{constclient=this.getAuthenticatedClient(accessToken);constuser=awaitclient.api('/me').select('displayName,mail,userPrincipalName').get();returnuser;}privatehandleLogin=(instance: IPublicClientApplication)=>{instance.loginRedirect(loginRequest).catch(e=>{console.error(e);});}privatehandleLogout=(instance: IPublicClientApplication)=>{instance.logout().catch(e=>{console.error(e);});}}

GOOGLE

Check code!

import{AuthMethodKey}from'./auth.model';import{IAuth}from'./IAuth';import{googleConfig}from'../../services/google.config';import{loadGapiInsideDOM,loadAuth2WithProps}from'gapi-script';exportclassAuthGoogleimplementsIAuth{publictype: AuthMethodKey='GOOGLE';privateinstance: gapi.auth2.GoogleAuthBase|undefined;constructor(){console.log('starting auth google');this.initialize()}publicsignIn=async()=>{console.log('signIn google');if(!this.instance)awaitthis.initialize();awaitthis.instance?.attachClickHandler(document.body,{},this.onSuccess,this.onFailure);};publicsignOut=async()=>{console.log('signOut google');if(!this.instance)awaitthis.initialize();this.instance?.signOut();};publicisAuthenticated=async()=>{if(!this.instance)awaitthis.initialize();returnawait(!!this.instance&&this.instance.isSignedIn.get());};publicgetUser=async()=>{if(!this.instance)awaitthis.initialize();if(this.instance?.isSignedIn.get()){constgoogleUser=this.instance?.currentUser.get();return{username: googleUser.getBasicProfile().getName(),email: googleUser.getBasicProfile().getEmail(),photo: googleUser.getBasicProfile().getImageUrl(),}}returnundefined;}privateinitialize=async()=>{awaitloadGapiInsideDOM();this.instance=awaitloadAuth2WithProps(gapi,googleConfig);}privateonSuccess=(googleUser: gapi.auth2.GoogleUser)=>{// Do something on success authentication}privateonFailure=(error: string)=>{// Do something on failure authenticationalert(JSON.stringify(error));}}

INTERN

This authentication uses the SessionStorage to save the user, and simulate a process api.

Check code!

import{AuthUser,AuthMethodKey}from'./auth.model';import{IAuth}from'./IAuth';exportclassAuthInternimplementsIAuth{publictype: AuthMethodKey='INTERN';constructor(){console.log('starting auth intern');}publicsignIn=async(authUser?: AuthUser)=>{awaitthis.timeout(3000);if(authUser){sessionStorage.setItem('@Auth.email',authUser.email);return{email: authUser.email,username: authUser.email}}constuserStorage=sessionStorage.getItem('@Auth.email');if(userStorage!==null){return{email: userStorage,username: userStorage}}returnundefined;};publicsignOut=async()=>{sessionStorage.removeItem('@Auth.email')};publicisAuthenticated=()=>{constuserStorage=sessionStorage.getItem('@Auth.email');returnPromise.resolve(!!userStorage);};publicgetUser=async()=>{constuserStorage=awaitsessionStorage.getItem('@Auth.email');if(userStorage!==null){return{email: userStorage,username: 'User interno'};}returnundefined;}privatetimeout=(ms: number)=>{returnnewPromise(resolve=>setTimeout(resolve,ms));}}

Developed by Marcio Costa.

About

Multiple authentication with React (Microsoft and Google)

Topics

Resources

Stars

4 stars

Watchers

1 watching

Forks

Contributors

Languages