Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do you authenticate a VueJS app with Azure AD?

Tags:

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.

like image 278
Coreus Avatar asked Jun 08 '17 13:06

Coreus


People also ask

How do I authenticate an app using Azure AD?

Enable Azure Active Directory in your App Service app. Sign in to the Azure portal and navigate to your app. Select Authentication in the menu on the left. Click Add identity provider.

Does Azure AD provide authentication?

Azure AD Benefit 1 Azure Active Directory is a secure online authentication store, which can contain users and groups. Users have a username and a password which are used when you sign into an application that uses Azure AD for authentication.

How does Azure AD authenticate users?

The user enters their password into the Azure AD sign in page, and then selects the Sign in button. Azure AD, on receiving the request to sign in, places the username and password (encrypted by using the public key of the Authentication Agents) in a queue.


1 Answers

To solve this very problem, I leaned on ADAL JS. I've made a Vue + Vue-Router sample application available here - but I'll include the important pieces below.

In your package.json:

"dependencies": {     "adal-angular": "^1.0.15",     "vue": "^2.5.2",     "vue-router": "^3.0.1" }, 

A basic wrapper module for the ADAL JS library:

import AuthenticationContext from 'adal-angular/lib/adal.js'  const config = {   tenant: 'your aad tenant',   clientId: 'your aad application client id',   redirectUri: 'base uri for this application',   cacheLocation: 'localStorage' };  export default {   authenticationContext: null,   /**    * @return {Promise}    */   initialize() {     this.authenticationContext = new AuthenticationContext(config);      return new Promise((resolve, reject) => {       if (this.authenticationContext.isCallback(window.location.hash) || window.self !== window.top) {         // redirect to the location specified in the url params.         this.authenticationContext.handleWindowCallback();       }       else {         // try pull the user out of local storage         let user = this.authenticationContext.getCachedUser();          if (user) {           resolve();         }         else {           // no user at all - go sign in.           this.signIn();         }       }     });   },   /**    * @return {Promise.<String>} A promise that resolves to an ADAL token for resource access    */   acquireToken() {     return new Promise((resolve, reject) => {       this.authenticationContext.acquireToken('<azure active directory resource id>', (error, token) => {         if (error || !token) {           return reject(error);         } else {           return resolve(token);         }       });     });   },   /**    * Issue an interactive authentication request for the current user and the api resource.    */   acquireTokenRedirect() {     this.authenticationContext.acquireTokenRedirect('<azure active directory resource id>');   },   /**    * @return {Boolean} Indicates if there is a valid, non-expired access token present in localStorage.    */   isAuthenticated() {     // getCachedToken will only return a valid, non-expired token.     if (this.authenticationContext.getCachedToken(config.clientId)) { return true; }     return false;   },   /**    * @return An ADAL user profile object.    */   getUserProfile() {     return this.authenticationContext.getCachedUser().profile;   },   signIn() {     this.authenticationContext.login();   },   signOut() {     this.authenticationContext.logOut();   } } 

In the app's entry point (main.js if you used vue-cli):

import Vue from 'vue' import App from './App' import router from './router' import authentication from './authentication'  // Init adal authentication - then create Vue app. authentication.initialize().then(_ => {   /* eslint-disable no-new */   new Vue({     el: '#app',     router,     template: '<App/>',     components: { App }   }); }); 

For your Vue router configuration:

import Vue from 'vue' import Router from 'vue-router' import HelloWorld from '@/components/HelloWorld' import authentication from '../authentication'  Vue.use(Router)  const router = new Router({   mode: 'history',   routes: [     {       path: '/',       name: 'HelloWorld',       component: HelloWorld,       meta: {         requiresAuthentication: true       }     }   ] })  // Global route guard router.beforeEach((to, from, next) => {   if (to.matched.some(record => record.meta.requiresAuthentication)) {     // this route requires auth, check if logged in     if (authentication.isAuthenticated()) {       // only proceed if authenticated.       next();     } else {       authentication.signIn();     }   } else {     next();   } });  export default router; 

In your Vue components:

import authentication from './authentication' ... computed: {   isAuthenticated() {     return authentication.isAuthenticated();   } }, methods: {   logOut() {     authentication.signOut();   } } 

Add access token to request headers

The below is an example of a vue-resource http interceptor, but any method will do.

Vue.http.interceptors.push(function (request, next) {   auth.acquireToken().then(token => {     // Set default request headers for every request     request.headers.set('Content-Type', 'application/json');     request.headers.set('Ocp-Apim-Subscription-Key', 'api key');     request.headers.set('Authorization', 'Bearer ' + token)     // continue to next interceptor     next();   }); }); 

Hopefully this saves somebody a little time :)

like image 147
matt-ankerson Avatar answered Nov 10 '22 23:11

matt-ankerson