-
Notifications
You must be signed in to change notification settings - Fork 51
Integration with Azure App Service Authentication
Keita Onabuta edited this page May 22, 2023
·
2 revisions
To use Azure App Service Authentication, please replace AppContext.tsx
file as below. And we have to change UI implementation and Signout features that will be implemented soon.
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
import React, { useContext, createContext, useState, MouseEventHandler, useEffect } from "react";
import { AuthCodeMSALBrowserAuthenticationProvider } from "@microsoft/microsoft-graph-client/authProviders/authCodeMsalBrowser";
import { InteractionType, PublicClientApplication } from "@azure/msal-browser";
import { useMsal } from "@azure/msal-react";
import { Client } from '@microsoft/microsoft-graph-client';
import { User } from "microsoft-graph";
export interface AppUser {
displayName?: string;
email?: string;
avatar?: string;
}
export interface AppError {
message: string;
debug?: string;
}
export interface AccessToken {
accessToken?: string;
}
export interface sessionInfo {
sessionId?: string;
}
type AppContext = {
user?: AppUser;
error?: AppError;
accessToken?: AccessToken;
sessionId?: sessionInfo;
signIn?: MouseEventHandler<HTMLElement>;
signOut?: MouseEventHandler<HTMLElement>;
displayError?: Function;
clearError?: Function;
authProvider?: AuthCodeMSALBrowserAuthenticationProvider;
isAuthenticated?: boolean;
};
const appContext = createContext<AppContext>({
user: undefined,
error: undefined,
accessToken: undefined,
sessionId: undefined,
signIn: undefined,
signOut: undefined,
displayError: undefined,
clearError: undefined,
authProvider: undefined
});
export function useAppContext(): AppContext {
return useContext(appContext);
}
interface ProvideAppContextProps {
children: React.ReactNode;
}
export default function ProvideAppContext({ children }: ProvideAppContextProps) {
const auth = useProvideAppContext();
return <appContext.Provider value={auth}>{children}</appContext.Provider>;
}
function useProvideAppContext() {
const [userInfo, setUserInfo] = useState();
const msal = useMsal();
const [user, setUser] = useState<AppUser | undefined>(undefined);
const [error, setError] = useState<AppError | undefined>(undefined);
const [accessToken, setAccessToken] = useState<AccessToken | undefined>(undefined);
const [sessionId, setSessionId] = useState<sessionInfo | undefined>(undefined);
const [isAuthenticated, setIsAuthenticated] = useState(false);
const displayError = (message: string, debug?: string) => {
setError({ message, debug });
};
const clearError = () => {
setError(undefined);
};
// Used by the Graph SDK to authenticate API calls
const authProvider = new AuthCodeMSALBrowserAuthenticationProvider(msal.instance as PublicClientApplication, {
account: msal.instance.getActiveAccount()!,
scopes: ["user.read"],
interactionType: InteractionType.Popup
});
async function getAccessToken(): Promise<string | undefined> {
try {
console.log("Getting access token...")
const response = await fetch('/.auth/me');
const payload = await response.json();
return payload[0].access_token;
} catch (error) {
console.error('No accessToken could be found');
return undefined;
}
}
let graphClient : Client | undefined = undefined;
//create graphClient from access token from .auth/me
async function getGraphClient(accessToken: string) {
if (graphClient === undefined) {
graphClient = Client.init({
authProvider: (done) => {
done(null, accessToken);
}
});
}
return graphClient;
}
async function getUser(accessToken: string): Promise<User> {
const client = await getGraphClient(accessToken);
const user = await client.api('/me').get();
return user;
}
async function getProfilePhoto(accessToken: string): Promise<string> {
const client = await getGraphClient(accessToken);
const photo = await client.api('/me/photo/$value').get();
const url = window.URL || window.webkitURL;
return url.createObjectURL(photo);
}
useEffect(() => {
const checkUser = async () => {
if (!user) {
try {
//if access token exists, set it
const token = await getAccessToken();
const user = await getUser(token || "")
console.log("user:", user)
const avatar = await getProfilePhoto(token || "")
console.log("avatar:", avatar)
setUser({
displayName: user.displayName || "",
email: user.mail || "",
avatar: avatar || ""
});
setIsAuthenticated(true);
} catch (err:any) {
displayError("Error signing in", err.message);
}
}
};
checkUser();
}
);
async function getUserInfo() {
try {
const response = await fetch('/.auth/me');
const payload = await response.json();
const { clientPrincipal } = payload;
console.log(clientPrincipal)
return clientPrincipal;
} catch (error) {
console.error('No profile could be found');
return undefined;
}
}
const signIn = async () => {
//TODO: Will be deleted because we use Azure App Service Authentication / Easy Auth
};
const signOut = async () => {
// TODO: Sign out the user and redirect to the login page
};
return {
user,
error,
accessToken,
sessionId,```
signIn,
signOut,
displayError,
clearError,
authProvider,
isAuthenticated
};
}