Skip to content

Commit

Permalink
Merge pull request #741 from andrewconnell/msidentity-appTypes-implic…
Browse files Browse the repository at this point in the history
…itToAuthCodeFlow

msidentity app types module: migrate implicit to auth code flow
  • Loading branch information
suzannazhuang committed Oct 26, 2020
2 parents dd128d6 + 8262865 commit 65c49b6
Show file tree
Hide file tree
Showing 3 changed files with 82 additions and 124 deletions.
Binary file modified Identity/02 Application Types/01.pptx
Binary file not shown.
17 changes: 9 additions & 8 deletions Identity/02 Application Types/README.md
Expand Up @@ -10,7 +10,7 @@ The lab for this module is available in multiple units within the associated Mic

1. [Exercise - Single Page Applications](https://docs.microsoft.com/learn/modules/identity-application-types/3-exercise-single-page-applications)

> In this exercise, you’ll learn how to create and configure a single-page application that will use an Azure AD application to issue an authenticated request to Microsoft Graph using the OAuth 2.0 implicit grant flow.
> In this exercise, you’ll learn how to create and configure a single-page application that will use an Azure AD application to issue an authenticated request to Microsoft Graph using the OAuth 2.0 authorization code flow.
1. [Exercise - Web apps that sign in users & call APIs](https://docs.microsoft.com/learn/modules/identity-application-types/5-exercise-web-apps-call-apis)

Expand Down Expand Up @@ -40,13 +40,14 @@ This module has been recorded and is available in the Office Development YouTube

## Version history

| Version | Date | Comments |
| ------- | ----------------- | ------------------------------------------------ |
| 1.4 | September 7, 2020 | FY2021Q1 content refresh |
| 1.3 | August 17, 2020 | Incorporate Microsoft.Identity.Web NuGet package |
| 1.2 | May 26, 2020 | FY2020Q4 content refresh |
| 1.1 | March 10, 2020 | FY2020Q3 content refresh |
| 1.0 | December 16, 2019 | New module published |
| Version | Date | Comments |
| ------- | ----------------- | ----------------------------------------------------------- |
| 1.5 | October 26, 2020 | Replace SPA implicit flow with auth code flow in MSAL.js v2 |
| 1.4 | September 7, 2020 | FY2021Q1 content refresh |
| 1.3 | August 17, 2020 | Incorporate Microsoft.Identity.Web NuGet package |
| 1.2 | May 26, 2020 | FY2020Q4 content refresh |
| 1.1 | March 10, 2020 | FY2020Q3 content refresh |
| 1.0 | December 16, 2019 | New module published |

## Disclaimer

Expand Down
189 changes: 73 additions & 116 deletions Identity/02 Application Types/demos/01-spa/index.html
Expand Up @@ -7,9 +7,9 @@
<html>

<head>
<title>Microsoft Identity: Application Types</title>
<title>Getting Started with Microsoft identity</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/bluebird/3.7.2/bluebird.min.js"></script>
<script src="https://alcdn.msauth.net/lib/1.4.0/js/msal.min.js"></script>
<script src="https://alcdn.msauth.net/browser/2.4.0/js/msal-browser.js"></script>
</head>

<body>
Expand All @@ -22,15 +22,22 @@ <h2>Latest messages</h2>
<div id="messages"></div>
</div>
<script>
var ua = window.navigator.userAgent;
var msie = ua.indexOf('MSIE ');
var msie11 = ua.indexOf('Trident/');
var msedge = ua.indexOf('Edge/');
var isIE = msie > 0 || msie11 > 0;
var isEdge = msedge > 0;

var msalConfig = {
auth: {
clientId: '',
authority: '',
redirectURI: 'http://localhost:3007/'
redirectURI: 'http://localhost:3007'
},
cache: {
cacheLocation: "localStorage",
storeAuthStateInCookie: true
storeAuthStateInCookie: isIE || isEdge
}
};

Expand All @@ -41,85 +48,56 @@ <h2>Latest messages</h2>
}
};

var msalApplication = new Msal.UserAgentApplication(msalConfig);

// init the auth handling on the page
initPage();

var msalApplication = new msal.PublicClientApplication(msalConfig);
var userName = "";
var loginType = isIE ? "REDIRECT" : "POPUP";

msalApplication.handleRedirectCallback(authRedirectCallBack);
msalApplication.handleRedirectPromise()
.then(handleResponse)
.catch(function (error) { console.log(error); }
);
// TODO: add CODE before this line


// Update the welcome message &
// init the signin button
function updateWelcomeMessageAndSigninControl() {
// update welcome message
function updateUserInterface() {
var divWelcome = document.getElementById('WelcomeMessage');
divWelcome.innerHTML = `Welcome <strong>${msalApplication.getAccount().name}</strong> &lt;${msalApplication.getAccount().userName}&gt; to Microsoft Graph API`;
divWelcome.innerHTML = 'Welcome <strong>' + userName + '</strong> to Microsoft Graph API';

// update signin/out button
var loginbutton = document.getElementById('SignIn');
loginbutton.innerHTML = 'Sign Out';
loginbutton.setAttribute('onclick', 'signOut();');
}

function acquireTokenPopupAndGetUserEmails() {
// try to get token silently without logging in (ie: from token cache)
msalApplication.acquireTokenSilent(graphConfig.requestObj)
function acquireTokenAndGetUserEmails() {
var request = graphConfig.requestObj;
request.account = msalApplication.getAccountByUsername(userName);

msalApplication.acquireTokenSilent(request)
.then(function (tokenResponse) {
// request email messages from Microsoft Graph
getMessagesFromMSGraph(graphConfig.graphMeEndpoint + '/messages?$top=10&$select=subject', tokenResponse.accessToken, graphAPICallback);
}).catch(function (error) {
console.log(error);
if (requiresInteraction(error.errorCode)) {
// unable to get token silently, so log the user in interactively (ie: display popup)
msalApplication.acquireTokenPopup(graphConfig.requestObj).then(function (tokenResponse) {
// request email messages from Microsoft Graph
getMessagesFromMSGraph(graphConfig.graphMeEndpoint + '/messages?$top=10&$select=subject', tokenResponse.accessToken, graphAPICallback);
}).catch(function (error) {
console.log(error);
});
getMessagesFromMSGraph(tokenResponse.accessToken, graphAPICallback);
})
.catch(function (error) {
console.log("silent token acquisition fails.");
if (error instanceof msal.InteractionRequiredAuthError) {
if (loginType == "POPUP") {
msalApplication.acquireTokenPopup(request)
.then(function (tokenResponse) {
getMessagesFromMSGraph(tokenResponse.accessToken, graphAPICallback);
})
.catch(function (error) { console.error(error); }
);
} else {
msalApplication.acquireTokenRedirect(request);
}
} else {
console.error(error);
}
});
}

function acquireTokenRedirectAndGetUserEmails() {
// try to get token silently without logging in (ie: from token cache)
msalApplication.acquireTokenSilent(graphConfig.requestObj).then(function (tokenResponse) {
getMessagesFromMSGraph(graphConfig.graphMeEndpoint + '/messages?$top=10&$select=subject', tokenResponse.accessToken, graphAPICallback);
}).catch(function (error) {
console.log(error);
// unable to get token silently, so log the user in interactively (ie: display popup)
if (requiresInteraction(error.errorCode)) {
msalApplication.acquireTokenRedirect(graphConfig.requestObj);
}
});
}
function getMessagesFromMSGraph(accessToken, callback) {
var endpoint = graphConfig.graphMeEndpoint + "/messages?$top=10&$select=subject";

// Check the error code for the error returned to determine if interactive login required
function requiresInteraction(errorCode) {
if (!errorCode || !errorCode.length) {
return false;
}
return errorCode === "consent_required" ||
errorCode === "interaction_required" ||
errorCode === "login_required";
}

function authRedirectCallBack(error, response) {
if (error) {
console.log(error);
} else {
if (response.tokenType === "access_token") {
getMessagesFromMSGraph(graphConfig.graphMeEndpoint + '//messages?$top=10&$select=subject', response.accessToken, graphAPICallback);
} else {
console.log("token type is:" + response.tokenType);
}
}
}

function getMessagesFromMSGraph(endpoint, accessToken, callback) {
var xmlHttp = new XMLHttpRequest();
xmlHttp.onreadystatechange = function () {
if (this.readyState == 4 && this.status == 200)
Expand All @@ -130,7 +108,6 @@ <h2>Latest messages</h2>
xmlHttp.send();
}

// Process response from Microsoft Graph
function graphAPICallback(data) {
var htmlBody = '';
data.value.forEach(message => {
Expand All @@ -139,61 +116,41 @@ <h2>Latest messages</h2>
document.getElementById("messages").innerHTML = `<ul>${htmlBody}</ul>`;
}

function signIn() {
msalApplication.loginPopup(graphConfig.requestObj)
.then(function (loginResponse) {
updateWelcomeMessageAndSigninControl();
acquireTokenPopupAndGetUserEmails();
}).catch(function (error) {
console.log(error);
});
function handleResponse(loginResponse) {
if (loginResponse != null) {
userName = loginResponse.account.username;
} else {
var currentAccounts = msalApplication.getAllAccounts();
if (currentAccounts == null || currentAccounts.length == 0) {
return;
} else {
userName = currentAccounts[0].username;
}
}

updateUserInterface();
acquireTokenAndGetUserEmails();
}

function signOut() {
msalApplication.logout();
function signIn() {
if (loginType == "POPUP") {
msalApplication.loginPopup(graphConfig.requestObj)
.then(handleResponse)
.catch(function (error) { console.log(error); }
);
} else {
msalApplication.loginRedirect(graphConfig.requestObj);
}
}
// TODO: add FUNCTIONS before this line

function signOut() {
var logoutRequest = {
account: msalApplication.getAccountByUsername(userName)
};

function initPage() {
// Browser check variables
var ua = window.navigator.userAgent;
var msie = ua.indexOf('MSIE ');
var msie11 = ua.indexOf('Trident/');
var msedge = ua.indexOf('Edge/');
var isIE = msie > 0 || msie11 > 0;
var isEdge = msedge > 0;

// if you support IE, recommendation: sign in using Redirect APIs vs. popup
// Browser check variables
// can change this to default an experience outside browser use
var loginType = isIE ? "REDIRECT" : "POPUP";

// runs on page load, change config to try different login types to see what is best for your application
switch (isIE) {
case true:
document.getElementById("SignIn").onclick = function () {
msalApplication.loginRedirect(graphConfig.requestObj);
};

// avoid duplicate code execution on page load in case of iframe and popup window
if (msalApplication.getAccount() && !msalApplication.isCallback(window.location.hash)) {
updateUserInterface();
acquireTokenRedirectAndGetUser();
}
break;
case false:
// avoid duplicate code execution on page load in case of iframe and popup window
if (msalApplication.getAccount()) {
updateUserInterface();
acquireTokenPopupAndGetUser();
}
break;
default:
console.error('Please set a valid login type');
break;
}
msalApplication.logout(logoutRequest);
}
// TODO: add FUNCTIONS before this line
</script>
</body>

Expand Down

0 comments on commit 65c49b6

Please sign in to comment.