'How do you authenticate a VueJS app with Azure AD?
I'm setting up an app using the VueJS 2.x framework and it needs to authenticate users via the Azure Active Directory service. I already have "login info" (Auth and Token URLs) neccessary for the service.
So far, I've only encountered one article that shows the setup in VueJS, but it relies on a third party service (Auth0) - adding uneccessary convolution in the process.
How do you proceed when there aren't any VueJS npm modules that allow for doing authenticating easily? Or do you have to rely on a library outside of Vue like Adal JS?
Any suggestions would be helpful.
Solution 1:[1]
Disclaimer: I am the author of this plugin.
Use vue-adal via npm:
npm install vue-adal
Basic Usage
import Adal from 'vue-adal'
Vue.use(Adal, {
// This config gets passed along to Adal, so all settings available to adal can be used here.
config: {
// 'common' (multi-tenant gateway) or Azure AD Tenant ID
tenant: '<guid>',
// Application ID
clientId: '<guid>',
// Host URI
redirectUri: '<host addr>',
cacheLocation: 'localStorage'
},
// Set this to true for authentication on startup
requireAuthOnInitialize: true,
// Pass a vue-router object in to add route hooks with authentication and role checking
router: router
})
```
important: make sure to set the mode on your router to 'history' so that it doesn't use hashes! This will have implications on the serverside.
new Router({
mode: 'history', // Required for Adal library
... // Rest of router init
})
There are more instructions for use on npm, and instructions + a sample on github
Solution 2:[2]
I'm not sure that there is a library to help with security for Vue apps. However, we can easily leverage Adal.js for authentication.
I wrote a simple demo for your reference:
Index.html:
<html>
<head>
<script src="https://unpkg.com/vue"></script>
<script src="node_modules\adal-angular\lib\adal.js"></script>
<script src="config.js"></script>
<script>
var authContext = new AuthenticationContext(config);
function login() {
authContext.login();
}
function init(configOptions) {
if (configOptions) {
// redirect and logout_redirect are set to current location by default
var existingHash = window.location.hash;
var pathDefault = window.location.href;
if (existingHash) {
pathDefault = pathDefault.replace(existingHash, "");
}
configOptions.redirectUri = configOptions.redirectUri || pathDefault;
configOptions.postLogoutRedirectUri =
configOptions.postLogoutRedirectUri || pathDefault;
// create instance with given config
} else {
throw new Error("You must set configOptions, when calling init");
}
// loginresource is used to set authenticated status
updateDataFromCache(authContext.config.loginResource);
}
var _oauthData = {
isAuthenticated: false,
userName: "",
loginError: "",
profile: ""
};
var updateDataFromCache = function(resource) {
// only cache lookup here to not interrupt with events
var token = authContext.getCachedToken(resource);
_oauthData.isAuthenticated = token !== null && token.length > 0;
var user = authContext.getCachedUser() || { userName: "" };
_oauthData.userName = user.userName;
_oauthData.profile = user.profile;
_oauthData.loginError = authContext.getLoginError();
};
function saveTokenFromHash() {
var hash = window.location.hash;
var requestInfo = authContext.getRequestInfo(hash);
if (authContext.isCallback(hash)) {
// callback can come from login or iframe request
var requestInfo = authContext.getRequestInfo(hash);
authContext.saveTokenFromHash(requestInfo);
window.location.hash = "";
if (requestInfo.requestType !== authContext.REQUEST_TYPE.LOGIN) {
authContext.callback = window.parent.AuthenticationContext().callback;
}
}
}
function isAuthenticate() {
return _oauthData.isAuthenticated;
}
saveTokenFromHash();
init(config);
</script>
</head>
<body>
<div id="app">
<p v-if="_oauthData.isAuthenticated">Hello {{ oauthData.userName }}</p>
<button onclick="login()" v-else>Login</button>
</div>
<script>
var app = new Vue({
el: "#app",
data: {
oauthData: _oauthData
}
});
</script>
</body>
</html>
config.js:
var config = {
tenant: 'xxx.onmicrosoft.com',
clientId: '',
redirectUri: '',
cacheLocation: 'localStorage'
};
Solution 3:[3]
You can use Adal JavaScript. However, I suggest you to research more on security side for this solution, it doesn't seem to be in line with the new security recommendation, which is to use a PKCE (see https://oauth.net/2/grant-types/implicit/). I couldn't find any adal JavaScript documentation for that.
Solution 4:[4]
This was a hard one for me so I'm posting here - hopfully this will save some time to someone:
My problem was that I need not only to authenticate my vue.js app with azure-ad, but I need also to get the security groups to which the user is belonging to.
To achive this, this is what I done:
I used the vue-adal sample app mentioned above (you can find it in: https://github.com/survirtual/vue-adal) - under sample folder.
But I still had to make some changes to make it behave the way I need. The problem was that after logging in with my user the sample app used windows.net graph API for retrieving user info with the token from the user authentication, so I had to change in main.js this:
const graphApiBase = `https://graph.windows.net`
const graphApiResource = '00000002-0000-0000-c000-000000000000'
to this:
const graphApiBase = `https://graph.microsoft.com/v1.0`
const graphApiResource = '00000003-0000-0000-c000-000000000000'
In addition, inside the return url component I had to change the axios query to get the security groups to which the user belongs to ... so I changed this (in the home.vue file):
async getUserInfo () {
let res = await this.$graphApi.get(`me`, {
params: {
'api-version': 1.6
}
})
to this:
async getUserInfo () {
let res = await this.$graphApi.post(`/me/getMemberGroups`, {
securityEnabledOnly: true
})
console.log(res)
return res.data
}
And then the data that I received back from the API contained the security groups to which the user belongs to ...
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | |
| Solution 2 | MarredCheese |
| Solution 3 | double-beep |
| Solution 4 | m02ph3u5 |
