New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
msal-browser testing sample using msal-node to obtain tokens #2771
Merged
Merged
Changes from 2 commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
9398e70
Initial sample + test
tnorling bb8ef90
Change files
tnorling eadc36d
Add ropc warning to readme
tnorling 2d0fa4e
Merge branch 'dev' into test-msal-browser-example
tnorling 2938971
Merge branch 'dev' into test-msal-browser-example
tnorling File filter
Filter by extension
Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
There are no files selected for viewing
8 changes: 8 additions & 0 deletions
8
change/@azure-msal-node-2020-12-16-16-25-06-test-msal-browser-example.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
{ | ||
"type": "prerelease", | ||
"comment": "Add getKVStore to tokenCache (#2771)", | ||
"packageName": "@azure/msal-node", | ||
"email": "thomas.norling@microsoft.com", | ||
"dependentChangeType": "patch", | ||
"date": "2020-12-17T00:25:06.891Z" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
{ | ||
"presets": [ | ||
"@babel/preset-typescript", | ||
[ | ||
"@babel/preset-env", | ||
{ | ||
"modules": "commonjs" | ||
} | ||
] | ||
], | ||
"plugins": [ | ||
"@babel/proposal-class-properties", | ||
"@babel/proposal-object-rest-spread" | ||
] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
{ | ||
"shouldPublish": false | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
# MSAL.js Jest/Puppeteer Testing Example | ||
|
||
## About this sample | ||
|
||
This sample demonstrates how you can run e2e tests against an application that uses msal-browser to obtain tokens and sign users in. | ||
Using the [ROPC flow](https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-oauth-ropc) in [msal-node](https://github.com/AzureAD/microsoft-authentication-library-for-js/tree/dev/lib/msal-node) you can pre-populate local or session storage with tokens without requiring your test to navigate through the AAD sign-in pages. This allows you to test your application with a real user and real tokens without testing 3rd party sites. | ||
|
||
## Pre-requisites | ||
|
||
- Ensure the clientId and authority in `test/browser-test.spec.ts` (msal-node configuration) match what is set in `app/authConfig.js` (msal-browser configuration) | ||
- You must use a tenanted authority to use the ROPC flow | ||
- Implement a function to get a username and password for the test account | ||
- Ensure the `usernamePasswordRequest` request contains the same scopes your SPA needs tokens for, making several requests if needed. | ||
|
||
## Run the test | ||
|
||
```javascript | ||
// Install dependencies | ||
npm install | ||
// Run tests using jest and puppeteer | ||
npm test | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
// Browser check variables | ||
// If you support IE, our recommendation is that you sign-in using Redirect APIs | ||
// If you as a developer are testing using Edge InPrivate mode, please add "isEdge" to the if check | ||
const ua = window.navigator.userAgent; | ||
const msie = ua.indexOf("MSIE "); | ||
const msie11 = ua.indexOf("Trident/"); | ||
const msedge = ua.indexOf("Edge/"); | ||
const isIE = msie > 0 || msie11 > 0; | ||
const isEdge = msedge > 0; | ||
|
||
let signInType; | ||
let accountId = ""; | ||
|
||
// Create the main myMSALObj instance | ||
// configuration parameters are located at authConfig.js | ||
const myMSALObj = new msal.PublicClientApplication(msalConfig); | ||
|
||
// Redirect: once login is successful and redirects with tokens, call Graph API | ||
myMSALObj.handleRedirectPromise().then(handleResponse).catch(err => { | ||
console.error(err); | ||
}); | ||
|
||
function handleResponse(resp) { | ||
if (resp !== null) { | ||
accountId = resp.account.homeAccountId; | ||
showWelcomeMessage(resp.account); | ||
} else { | ||
// need to call getAccount here? | ||
const currentAccounts = myMSALObj.getAllAccounts(); | ||
if (!currentAccounts || currentAccounts.length < 1) { | ||
return; | ||
} else if (currentAccounts.length > 1) { | ||
// Add choose account code here | ||
} else if (currentAccounts.length === 1) { | ||
accountId = currentAccounts[0].homeAccountId; | ||
showWelcomeMessage(currentAccounts[0]); | ||
} | ||
} | ||
} | ||
|
||
async function signIn(method) { | ||
signInType = isIE ? "loginRedirect" : method; | ||
if (signInType === "loginPopup") { | ||
return myMSALObj.loginPopup(loginRequest).then(handleResponse).catch(function (error) { | ||
console.log(error); | ||
}); | ||
} else if (signInType === "loginRedirect") { | ||
return myMSALObj.loginRedirect(loginRequest) | ||
} | ||
} | ||
|
||
function signOut() { | ||
const logoutRequest = { | ||
account: myMSALObj.getAccountByHomeId(accountId) | ||
}; | ||
|
||
myMSALObj.logout(logoutRequest); | ||
} | ||
|
||
async function getTokenPopup(request, account) { | ||
request.account = account; | ||
return await myMSALObj.acquireTokenSilent(request).catch(async (error) => { | ||
console.log("silent token acquisition fails."); | ||
if (error instanceof msal.InteractionRequiredAuthError) { | ||
console.log("acquiring token using popup"); | ||
return myMSALObj.acquireTokenPopup(request).catch(error => { | ||
console.error(error); | ||
}); | ||
} else { | ||
console.error(error); | ||
} | ||
}); | ||
} | ||
|
||
// This function can be removed if you do not need to support IE | ||
async function getTokenRedirect(request, account) { | ||
request.account = account; | ||
return await myMSALObj.acquireTokenSilent(request).catch(async (error) => { | ||
console.log("silent token acquisition fails."); | ||
if (error instanceof msal.InteractionRequiredAuthError) { | ||
// fallback to interaction when silent call fails | ||
console.log("acquiring token using redirect"); | ||
myMSALObj.acquireTokenRedirect(request); | ||
} else { | ||
console.error(error); | ||
} | ||
}); | ||
} |
55 changes: 55 additions & 0 deletions
55
samples/msal-browser-samples/TestingSample/app/authConfig.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
// Config object to be passed to Msal on creation | ||
const msalConfig = { | ||
auth: { | ||
clientId: "client_id_here", | ||
authority: "tenanted_authority_here" | ||
}, | ||
cache: { | ||
cacheLocation: "sessionStorage", // This configures where your cache will be stored | ||
storeAuthStateInCookie: false, // Set this to "true" if you are having issues on IE11 or Edge | ||
}, | ||
system: { | ||
loggerOptions: { | ||
loggerCallback: (level, message, containsPii) => { | ||
if (containsPii) { | ||
return; | ||
} | ||
switch (level) { | ||
case msal.LogLevel.Error: | ||
console.error(message); | ||
return; | ||
case msal.LogLevel.Info: | ||
console.info(message); | ||
return; | ||
case msal.LogLevel.Verbose: | ||
console.debug(message); | ||
return; | ||
case msal.LogLevel.Warning: | ||
console.warn(message); | ||
return; | ||
} | ||
} | ||
} | ||
} | ||
}; | ||
|
||
// Add here scopes for id token to be used at MS Identity Platform endpoints. | ||
const loginRequest = { | ||
scopes: ["User.Read"] | ||
}; | ||
|
||
// Add here the endpoints for MS Graph API services you would like to use. | ||
const graphConfig = { | ||
graphMeEndpoint: "https://graph.microsoft.com/v1.0/me", | ||
graphMailEndpoint: "https://graph.microsoft.com/v1.0/me/messages" | ||
}; | ||
|
||
// Add here scopes for access token to be used at MS Graph API endpoints. | ||
const tokenRequest = { | ||
scopes: ["Mail.Read"], | ||
forceRefresh: false // Set this to "true" to skip a cached token and go to the server to get a new token | ||
}; | ||
|
||
const silentRequest = { | ||
scopes: ["openid", "profile", "User.Read", "Mail.Read"] | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
// Helper function to call MS Graph API endpoint | ||
// using authorization bearer token scheme | ||
function callMSGraph(endpoint, accessToken, callback) { | ||
const headers = new Headers(); | ||
const bearer = `Bearer ${accessToken}`; | ||
|
||
headers.append("Authorization", bearer); | ||
|
||
const options = { | ||
method: "GET", | ||
headers: headers | ||
}; | ||
|
||
console.log('request made to Graph API at: ' + new Date().toString()); | ||
|
||
fetch(endpoint, options) | ||
.then(response => response.json()) | ||
.then(response => callback(response, endpoint)) | ||
.catch(error => console.log(error)); | ||
} | ||
|
||
async function seeProfile() { | ||
const currentAcc = myMSALObj.getAccountByHomeId(accountId); | ||
if (currentAcc) { | ||
const response = await getTokenPopup(loginRequest, currentAcc).catch(error => { | ||
console.log(error); | ||
}); | ||
callMSGraph(graphConfig.graphMeEndpoint, response.accessToken, updateUI); | ||
profileButton.style.display = 'none'; | ||
} | ||
} | ||
|
||
async function readMail() { | ||
const currentAcc = myMSALObj.getAccountByHomeId(accountId); | ||
if (currentAcc) { | ||
const response = await getTokenPopup(tokenRequest, currentAcc).catch(error => { | ||
console.log(error); | ||
}); | ||
callMSGraph(graphConfig.graphMailEndpoint, response.accessToken, updateUI); | ||
mailButton.style.display = 'none'; | ||
} | ||
} | ||
|
||
async function seeProfileRedirect() { | ||
const currentAcc = myMSALObj.getAccountByHomeId(accountId); | ||
if (currentAcc) { | ||
const response = await getTokenRedirect(loginRequest, currentAcc).catch(error => { | ||
console.log(error); | ||
}); | ||
callMSGraph(graphConfig.graphMeEndpoint, response.accessToken, updateUI); | ||
profileButton.style.display = 'none'; | ||
} | ||
} | ||
|
||
async function readMailRedirect() { | ||
const currentAcc = myMSALObj.getAccountByHomeId(accountId); | ||
if (currentAcc) { | ||
const response = await getTokenRedirect(tokenRequest, currentAcc).catch(error => { | ||
console.log(error); | ||
}); | ||
callMSGraph(graphConfig.graphMailEndpoint, response.accessToken, updateUI); | ||
mailButton.style.display = 'none'; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
<!DOCTYPE html> | ||
<html lang="en"> | ||
<head> | ||
<meta charset="UTF-8"> | ||
<meta name="viewport" content="width=device-width, initial-scale=1.0, shrink-to-fit=no"> | ||
<title>Quickstart | MSAL.JS Vanilla JavaScript SPA</title> | ||
|
||
<script type="text/javascript" src="https://alcdn.msauth.net/browser/2.8.0/js/msal-browser.min.js"></script> | ||
|
||
<!-- adding Bootstrap 4 for UI components --> | ||
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous"> | ||
<link rel="SHORTCUT ICON" href="https://c.s-microsoft.com/favicon.ico?v2" type="image/x-icon"> | ||
</head> | ||
<body> | ||
<nav class="navbar navbar-expand-lg navbar-dark bg-primary"> | ||
<a class="navbar-brand" href="/">MS Identity Platform</a> | ||
<div class="btn-group ml-auto dropleft"> | ||
<button type="button" id="SignIn" class="btn btn-secondary dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> | ||
Sign In | ||
</button> | ||
<div class="dropdown-menu"> | ||
<button class="dropdown-item" id="loginPopup" onclick="signIn(this.id)">Sign in using Popup</button> | ||
<button class="dropdown-item" id="loginRedirect" onclick="signIn(this.id)">Sign in using Redirect</button> | ||
</div> | ||
</div> | ||
</nav> | ||
<br> | ||
<h5 class="card-header text-center">Vanilla JavaScript SPA calling MS Graph API with MSAL.JS</h5> | ||
<br> | ||
<div class="row" style="margin:auto" > | ||
<div id="card-div" class="col-md-3" style="display:none"> | ||
<div class="card text-center"> | ||
<div class="card-body"> | ||
<h5 class="card-title" id="WelcomeMessage">Please sign-in to see your profile and read your mails</h5> | ||
<div id="profile-div"></div> | ||
<br> | ||
<br> | ||
<button class="btn btn-primary" id="seeProfile" onclick="seeProfile()">See Profile</button> | ||
<br> | ||
<br> | ||
<button class="btn btn-primary" id="readMail" onclick="readMail()">Read Mails</button> | ||
</div> | ||
</div> | ||
</div> | ||
<br> | ||
<br> | ||
<div class="col-md-4"> | ||
<div class="list-group" id="list-tab" role="tablist"> | ||
</div> | ||
</div> | ||
<div class="col-md-5"> | ||
<div class="tab-content" id="nav-tabContent"> | ||
</div> | ||
</div> | ||
</div> | ||
<br> | ||
<br> | ||
|
||
<!-- importing bootstrap.js and supporting js libraries --> | ||
<script src="https://code.jquery.com/jquery-3.4.1.slim.min.js" integrity="sha384-J6qa4849blE2+poT4WnyKhv5vZF5SrPo0iEjwBvKU7imGFAV0wwj1yYfoRSJoZ+n" crossorigin="anonymous"></script> | ||
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script> | ||
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js" integrity="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6" crossorigin="anonymous"></script> | ||
|
||
<!-- importing app scripts | load order is important --> | ||
<script type="text/javascript" src="./authConfig.js"></script> | ||
<script type="text/javascript" src="./ui.js"></script> | ||
<script type="text/javascript" src="./auth.js"></script> | ||
<script type="text/javascript" src="./graph.js"></script> | ||
</body> | ||
</html> |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you think we should add tests for this?