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:
- INTERN - Using your own authentication api;
- AZURE - Using Microsoft authentication;
- GOOGLE - Using Google authentication;
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
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:3000Follow these tutorials to get the clientId keys:
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;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>;}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);});}}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));}}This authentication uses the SessionStorage to save the user, and simulate a process api.
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.
