Skip to content
This repository has been archived by the owner. It is now read-only.

Commit 74d6b6b

Browse files
committed
Incorporating feedback and code refactoring (core)
1 parent cd9c1bc commit 74d6b6b

File tree

2 files changed

+104
-117
lines changed

2 files changed

+104
-117
lines changed

JavaScriptSPA/app.js

Lines changed: 79 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -1,68 +1,47 @@
1-

2-
var graphAPIMeEndpoint = "https://graph.microsoft.com/v1.0/me";
1+
// Graph API endpoint to show user profile
2+
var graphApiEndpoint = "https://graph.microsoft.com/v1.0/me";
3+
4+
// Graph API scope used to obtain the access token to read user profile
35
var graphAPIScopes = ["https://graph.microsoft.com/user.read"];
46

57
// Initialize application
6-
var userAgentApplication = new Msal.UserAgentApplication(msalconfig.clientID, null, displayUserInfo, {
8+
var userAgentApplication = new Msal.UserAgentApplication(msalconfig.clientID, null, loginCallback, {
79
redirectUri: msalconfig.redirectUri
810
});
911

1012
//Previous version of msal uses redirect url via a property
11-
if (userAgentApplication.redirectUri) userAgentApplication.redirectUri = msalconfig.redirectUri;
13+
if (userAgentApplication.redirectUri) {
14+
userAgentApplication.redirectUri = msalconfig.redirectUri;
15+
}
1216

13-
var user = userAgentApplication.getUser();
1417
window.onload = function () {
15-
//Add support to display user info in case of reload of the page
18+
// If page is refreshed, continue to display user info
1619
if (!userAgentApplication.isCallback(window.location.hash) && window.parent === window && !window.opener) {
20+
var user = userAgentApplication.getUser();
1721
if (user) {
18-
displayUserInfo();
22+
callGraphApi();
1923
}
2024
}
21-
2225
}
2326

24-
/**
25-
* Display the results from Web API call in json format
26-
*
27-
* @param {object} data - Results from API call
28-
* @param {object} token - The access token
29-
* @param {object} responseElement - HTML element to show the results
30-
* @param {object} showTokenElement - HTML element to show the RAW token
31-
*/
32-
function showAPIResponse(data, token, responseElement, showTokenElement) {
33-
console.log(data);
34-
responseElement.innerHTML = JSON.stringify(data, null, 4);
35-
if (showTokenElement) {
36-
showTokenElement.parentElement.classList.remove("hidden");
37-
showTokenElement.innerHTML = token;
38-
}
39-
}
40-
41-
/**
42-
* Show an error message in the page
43-
* @param {any} endpoint - the endpoint used for the error message
44-
* @param {any} error - the error string
45-
* @param {any} errorElement - the HTML element in the page to display the error
46-
*/
47-
function showError(endpoint, error, errorElement) {
48-
console.error(error);
49-
var formattedError = JSON.stringify(error, null, 4);
50-
if (formattedError.length < 3) {
51-
formattedError = error;
52-
}
53-
errorElement.innerHTML = "Error calling " + endpoint + ": " + formattedError;
54-
}
5527

5628
/**
57-
* Displays user information based on the information contained in the id token
58-
* And also calls the method to display the user profile via Microsoft Graph API
29+
* Call the Microsoft Graph API and display the results on the page
5930
*/
60-
function displayUserInfo() {
31+
function callGraphApi() {
6132
var user = userAgentApplication.getUser();
6233
if (!user) {
63-
//If user is not signed in, then prompt user to sing-in via loginRedirect
34+
// If user is not signed in, then prompt user to sign in via loginRedirect.
35+
// This will redirect user to the Azure Active Directory v2 Endpoint
6436
userAgentApplication.loginRedirect(graphAPIScopes);
37+
38+
// The call to loginRedirect above frontloads the consent to query Graph API during the sign-in.
39+
// If you want to use dynamic consent, just remove the graphAPIScopes from loginRedirect call:
40+
// As such, user will be prompted to give consent as soon as the token for a resource that
41+
// he/she hasn't consented before is requested. In the case of this application -
42+
// the first time the Graph API call to obtain user's profile is executed.
6543
} else {
44+
6645
// If user is already signed in, display the user info
6746
var userInfoElement = document.getElementById("userInfo");
6847
userInfoElement.parentElement.classList.remove("hidden");
@@ -71,59 +50,60 @@ function displayUserInfo() {
7150
// Show Sign-Out button
7251
document.getElementById("signOutButton").classList.remove("hidden");
7352

74-
//Now Call Graph API to show the user profile information
75-
callGraphAPI();
53+
// Now Call Graph API to show the user profile information:
54+
var graphCallResponseElement = document.getElementById("graphResponse");
55+
graphCallResponseElement.parentElement.classList.remove("hidden");
56+
graphCallResponseElement.innerText = "Calling Graph ...";
57+
58+
// In order to call the Graph API, an access token needs to be acquired.
59+
// Try to acquire the token used to Query Graph API silently first
60+
userAgentApplication.acquireTokenSilent(graphAPIScopes)
61+
.then(function (token) {
62+
//After the access token is acquired, call the Web API, sending the acquired token
63+
callWebApiWithToken(graphApiEndpoint, token, graphCallResponseElement, document.getElementById("accessToken"));
64+
65+
}, function (error) {
66+
// If the acquireTokenSilent() method fails, then acquire the token interactively via acquireTokenRedirect().
67+
// In this case, the browser will redirect user back to the Azure Active Directory v2 Endpoint so the user
68+
// can re-type the current username and password and/ or give consent to new permissions your application is requesting.
69+
// After authentication/ authorization completes, this page will be reloaded again and callGraphApi() will be called.
70+
// Then, acquireTokenSilent will then acquire the token silently, the Graph API call results will be made and results will be displayed in the page.
71+
if (error) {
72+
userAgentApplication.acquireTokenRedirect(graphAPIScopes);
73+
}
74+
});
75+
7676
}
7777
}
7878

7979
/**
80-
* Call the Microsoft Graph API and display the results on the page
80+
* Show an error message in the page
81+
* @param {string} endpoint - the endpoint used for the error message
82+
* @param {string} error - the error string
83+
* @param {object} errorElement - the HTML element in the page to display the error
8184
*/
82-
function callGraphAPI() {
83-
var user = userAgentApplication.getUser();
84-
if (user) {
85-
var responseElement = document.getElementById("graphResponse");
86-
responseElement.parentElement.classList.remove("hidden");
87-
responseElement.innerText = "Calling Graph ...";
88-
callWebApiWithScope(graphAPIMeEndpoint,
89-
graphAPIScopes,
90-
responseElement,
91-
document.getElementById("errorMessage"),
92-
document.getElementById("accessToken"));
93-
} else {
94-
showError(graphAPIMeEndpoint, "User has not signed-in", document.getElementById("errorMessage"));
85+
function showError(endpoint, error, errorDesc) {
86+
var formattedError = JSON.stringify(error, null, 4);
87+
if (formattedError.length < 3) {
88+
formattedError = error;
9589
}
90+
document.getElementById("errorMessage").innerHTML = "An error has occurred:<br/>Endpoint: " + endpoint + "<br/>Error: " + formattedError + "<br/>" + errorDesc;
91+
console.error(error);
9692
}
9793

9894
/**
99-
* Call a Web API that requires scope, then display the response
100-
*
101-
* @param {string} endpoint - The Web API endpoint
102-
* @param {object} scope - An array containing the API scopes
103-
* @param {object} responseElement - HTML element used to display the results
104-
* @param {object} errorElement = HTML element used to display an error message
105-
* @param {object} showTokenElement = HTML element used to display the RAW access token
95+
* Callback method from sign-in: if no errors, call callGraphApi() to show results.
96+
* @param {string} errorDesc - If error occur, the error message
97+
* @param {object} token - The token received from login
98+
* @param {object} error - The error
99+
* @param {string} tokenType - the token type: usually id_token
106100
*/
107-
function callWebApiWithScope(endpoint, scope, responseElement, errorElement, showTokenElement) {
108-
//Try to acquire the token silently first
109-
userAgentApplication.acquireTokenSilent(scope)
110-
.then(function (token) {
111-
//After the access token is acquired, call the Web API, sending the acquired token
112-
callWebApiWithToken(endpoint, token, responseElement, errorElement, showTokenElement);
113-
}, function (error) {
114-
//If the acquireTokenSilent fails, then acquire the token interactively via acquireTokenPopup
115-
if (error) {
116-
userAgentApplication.acquireTokenPopup(scope).then(function (token) {
117-
//After the access token is acquired, call the Web API, sending the acquired token
118-
callWebApiWithToken(endpoint, token, responseElement, errorElement, showTokenElement);
119-
},
120-
function (error) {
121-
showError(endpoint, error, errorElement);
122-
});
123-
} else {
124-
showError(endpoint, error, errorElement);
125-
}
126-
});
101+
function loginCallback(errorDesc, token, error, tokenType) {
102+
if (errorDesc) {
103+
showError(msal.authority, error, errorDesc);
104+
} else {
105+
callGraphApi();
106+
}
127107
}
128108

129109
/**
@@ -132,10 +112,9 @@ function callWebApiWithScope(endpoint, scope, responseElement, errorElement, sho
132112
* @param {any} endpoint - Web API endpoint
133113
* @param {any} token - Access token
134114
* @param {object} responseElement - HTML element used to display the results
135-
* @param {object} errorElement = HTML element used to display an error message
136115
* @param {object} showTokenElement = HTML element used to display the RAW access token
137116
*/
138-
function callWebApiWithToken(endpoint, token, responseElement, errorElement, showTokenElement) {
117+
function callWebApiWithToken(endpoint, token, responseElement, showTokenElement) {
139118
var headers = new Headers();
140119
var bearer = "Bearer " + token;
141120
headers.append("Authorization", bearer);
@@ -144,35 +123,40 @@ function callWebApiWithToken(endpoint, token, responseElement, errorElement, sho
144123
headers: headers
145124
};
146125

147-
// Note that fetch API is not available in all browsers
148126
fetch(endpoint, options)
149127
.then(function (response) {
150128
var contentType = response.headers.get("content-type");
151129
if (response.status === 200 && contentType && contentType.indexOf("application/json") !== -1) {
152130
response.json()
153131
.then(function (data) {
154132
// Display response in the page
155-
showAPIResponse(data, token, responseElement, showTokenElement);
133+
console.log(data);
134+
responseElement.innerHTML = JSON.stringify(data, null, 4);
135+
if (showTokenElement) {
136+
showTokenElement.parentElement.classList.remove("hidden");
137+
showTokenElement.innerHTML = token;
138+
}
156139
})
157140
.catch(function (error) {
158-
showError(endpoint, error, errorElement);
141+
showError(endpoint, error);
159142
});
160143
} else {
161144
response.json()
162145
.then(function (data) {
163-
// Display response in the page
164-
showError(endpoint, data, errorElement);
146+
// Display response as error in the page
147+
showError(endpoint, data);
165148
})
166149
.catch(function (error) {
167-
showError(endpoint, error, errorElement);
150+
showError(endpoint, error);
168151
});
169152
}
170153
})
171154
.catch(function (error) {
172-
showError(endpoint, error, errorElement);
155+
showError(endpoint, error);
173156
});
174157
}
175158

159+
176160
/**
177161
* Sign-out the user
178162
*/

JavaScriptSPA/index.html

Lines changed: 25 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,37 @@
11
<!DOCTYPE html>
22
<html>
33
<head>
4+
<!-- bootstrap reference used for styling the page -->
45
<link href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
56
<title>JavaScript SPA Guided Setup</title>
67
</head>
78
<body style="margin: 40px">
8-
<button id="callGraphButton" type="button" class="btn btn-primary" onclick="displayUserInfo()">Call Microsoft Graph API</button>
9-
<div id="errorMessage" class="text-danger"></div>
10-
<div class="hidden">
11-
<h3>Graph API Call Response</h3>
12-
<pre class="well" id="graphResponse"></pre>
13-
</div>
14-
<div class="hidden">
15-
<h3>Access Token</h3>
16-
<pre class="well" id="accessToken"></pre>
17-
</div>
18-
<div class="hidden">
19-
<h3>ID Token Claims</h3>
20-
<pre class="well" id="userInfo"></pre>
21-
</div>
22-
<button id="signOutButton" type="button" class="btn btn-primary hidden" onclick="signOut()">Sign out</button>
9+
<button id="callGraphButton" type="button" class="btn btn-primary" onclick="callGraphApi()">Call Microsoft Graph API</button>
10+
<div id="errorMessage" class="text-danger"></div>
11+
<div class="hidden">
12+
<h3>Graph API Call Response</h3>
13+
<pre class="well" id="graphResponse"></pre>
14+
</div>
15+
<div class="hidden">
16+
<h3>Access Token</h3>
17+
<pre class="well" id="accessToken"></pre>
18+
</div>
19+
<div class="hidden">
20+
<h3>ID Token Claims</h3>
21+
<pre class="well" id="userInfo"></pre>
22+
</div>
23+
<button id="signOutButton" type="button" class="btn btn-primary hidden" onclick="signOut()">Sign out</button>
2324

24-
<script src="//secure.aadcdn.microsoftonline-p.com/lib/0.1.1/js/msal.min.js"></script>
25-
<script type="text/javascript" src="msalconfig.js"></script>
25+
<!-- This app uses cdn to reference msal.js (recommended).
26+
You can also download it from: https://github.com/AzureAD/microsoft-authentication-library-for-js -->
27+
<script src="//secure.aadcdn.microsoftonline-p.com/lib/0.1.1/js/msal.min.js"></script>
28+
<!--<script type="text/javascript" src="msal.js"></script>-->
29+
<script type="text/javascript" src="msalconfig.js"></script>
2630

27-
<!-- The 'bluebird' and 'fetch' references below are required if you need to run this application on Internet Explorer -->
28-
<script src="//cdnjs.cloudflare.com/ajax/libs/bluebird/3.3.4/bluebird.min.js"></script>
29-
<script src="//cdnjs.cloudflare.com/ajax/libs/fetch/2.0.3/fetch.min.js"></script>
30-
31-
<script type="text/javascript" src="app.js"></script>
31+
<!-- The 'bluebird' and 'fetch' references below are required if you need to run this application on Internet Explorer -->
32+
<script src="//cdnjs.cloudflare.com/ajax/libs/bluebird/3.3.4/bluebird.min.js"></script>
33+
<script src="//cdnjs.cloudflare.com/ajax/libs/fetch/2.0.3/fetch.min.js"></script>
3234

35+
<script type="text/javascript" src="app.js"></script>
3336
</body>
3437
</html>

0 commit comments

Comments
 (0)