Chat
Ask me anything
Ithy Logo

Implementing Single Sign-On (SSO) with Azure AD in Vue.js

Step-by-step guide to integrating Azure Active Directory authentication in your Vue.js application

vuejs azure ad authentication

Key Takeaways

  • Comprehensive Setup: From Azure AD app registration to Vue.js configuration using MSAL.js.
  • Secure Authentication: Implementing login/logout methods, protecting routes, and managing tokens securely.
  • Seamless User Experience: Ensuring smooth SSO flow and session management for your application users.

Prerequisites

Before you begin implementing Single Sign-On (SSO) using Azure Active Directory (Azure AD) in your Vue.js application, ensure you have the following:

  • Node.js and npm: Ensure that Node.js and npm are installed on your development machine. You can download them from the official Node.js website.
  • Vue CLI: Install Vue CLI globally if you haven't already:
    npm install -g @vue/cli
  • Azure Account: An active Azure account with access to Azure Active Directory.
  • Registered Azure AD Application: An application registered in Azure AD to enable SSO.

Step 1: Register Your Application in Azure AD

1.1. Access Azure Portal

Navigate to the Azure Portal and sign in with your Azure account credentials.

1.2. Navigate to Azure Active Directory

Once signed in, go to the sidebar and select Azure Active Directory.

1.3. Register a New Application

  1. In the Azure Active Directory pane, select App registrations from the sidebar, then click on New registration.

  2. Fill out the registration form:

    • Name: Enter a meaningful name for your application, e.g., "Vue.js SSO App".
    • Supported account types: Choose the appropriate option based on your organization's needs.
    • Redirect URI: Select Single-page application (SPA) and enter your application's URL, e.g., http://localhost:8080 for local development.

  3. Click Register to create the application.

1.4. Configure Authentication Settings

  1. After registration, navigate to the Authentication section.

  2. Under Redirect URIs, ensure your application's URI is listed. If not, add it.

  3. Enable ID tokens by checking the box for Access tokens and ID tokens as part of the implicit grant flow.

1.5. Note Down Essential Identifiers

From the application's overview page, note the following values as they will be needed in your Vue.js application:

  • Application (client) ID
  • Directory (tenant) ID
  • Redirect URI

Step 2: Set Up Your Vue.js Project

2.1. Create a New Vue.js Application

vue create my-sso-app
cd my-sso-app

2.2. Install MSAL.js Library

Install the Microsoft Authentication Library (MSAL) for JavaScript using npm:

npm install @azure/msal-browser

Step 3: Configure MSAL in Your Vue.js Application

3.1. Create Authentication Configuration File

Create a new file named authConfig.js inside a dedicated src/auth directory to store your Azure AD configuration:


export const msalConfig = {
    auth: {
        clientId: "YOUR_CLIENT_ID", // Replace with your Azure AD app's Client ID
        authority: "https://login.microsoftonline.com/YOUR_TENANT_ID", // Replace with your Tenant ID
        redirectUri: "http://localhost:8080", // Replace with your app's redirect URI
    },
    cache: {
        cacheLocation: "sessionStorage", // Can also be 'localStorage'
        storeAuthStateInCookie: true, // Recommended for IE/Edge
    },
};

export const loginRequest = {
    scopes: ["User.Read"], // Define the permissions your app requires
};
  

3.2. Initialize MSAL in Your Main Application File

Modify src/main.js to initialize MSAL and make it available throughout your Vue application:


import { createApp } from 'vue';
import App from './App.vue';
import { PublicClientApplication } from '@azure/msal-browser';
import { msalConfig } from './auth/authConfig';

const msalInstance = new PublicClientApplication(msalConfig);

const app = createApp(App);

// Optionally, add MSAL instance to Vue's global properties
app.config.globalProperties.$msal = msalInstance;

app.mount('#app');
  

Step 4: Implement Authentication Methods

4.1. Create Authentication Service

Create a new file named authService.js inside src/auth to manage authentication logic:


import { PublicClientApplication } from "@azure/msal-browser";
import { msalConfig, loginRequest } from "./authConfig";

class AuthService {
    constructor() {
        this.msalInstance = new PublicClientApplication(msalConfig);
    }

    async login() {
        try {
            const loginResponse = await this.msalInstance.loginPopup(loginRequest);
            return loginResponse;
        } catch (error) {
            console.error("Login failed:", error);
            return null;
        }
    }

    logout() {
        this.msalInstance.logout();
    }

    getAccount() {
        const accounts = this.msalInstance.getAllAccounts();
        if (accounts.length > 0) {
            return accounts[0];
        }
        return null;
    }

    async acquireToken() {
        const account = this.getAccount();
        if (!account) {
            return null;
        }

        const tokenRequest = {
            scopes: ["User.Read"],
            account: account,
        };

        try {
            const tokenResponse = await this.msalInstance.acquireTokenSilent(tokenRequest);
            return tokenResponse.accessToken;
        } catch (error) {
            console.warn("Silent token acquisition failed, acquiring token via popup:", error);
            try {
                const tokenResponse = await this.msalInstance.acquireTokenPopup(tokenRequest);
                return tokenResponse.accessToken;
            } catch (popupError) {
                console.error("Token acquisition via popup failed:", popupError);
                return null;
            }
        }
    }
}

export const authService = new AuthService();
  

4.2. Create Login Component

Create a new Vue component named Login.vue inside src/components to handle user login and logout:


<template>
  <div>
    <button v-if="!isAuthenticated" @click="login">Login</button>
    <div v-else>
      <p>Welcome, {{ userName }}!</p>
      <button @click="logout">Logout</button>
    </div>
  </div>
</template>

<script>
import { ref, onMounted } from 'vue';
import { authService } from '../auth/authService';

export default {
    name: 'Login',
    setup() {
        const isAuthenticated = ref(false);
        const userName = ref('');

        const login = async () => {
            const response = await authService.login();
            if (response) {
                isAuthenticated.value = true;
                userName.value = response.account.username;
            }
        };

        const logout = () => {
            authService.logout();
            isAuthenticated.value = false;
            userName.value = '';
        };

        onMounted(() => {
            const account = authService.getAccount();
            if (account) {
                isAuthenticated.value = true;
                userName.value = account.username;
            }
        });

        return {
            isAuthenticated,
            userName,
            login,
            logout
        };
    }
};
</script>
  

Step 5: Protecting Routes with Vue Router

5.1. Install Vue Router

If Vue Router isn't already installed in your project, install it using npm:

npm install vue-router@4

5.2. Configure Vue Router

Create or modify src/router/index.js to set up route protection:


import { createRouter, createWebHistory } from 'vue-router';
import Home from '../components/Home.vue';
import Login from '../components/Login.vue';
import { authService } from '../auth/authService';

const routes = [
    {
        path: '/',
        name: 'Home',
        component: Home,
        meta: { requiresAuth: true }
    },
    {
        path: '/login',
        name: 'Login',
        component: Login
    },
    // Add more routes as needed
];

const router = createRouter({
    history: createWebHistory(),
    routes
});

// Navigation Guard to Protect Routes
router.beforeEach(async (to, from, next) => {
    if (to.meta.requiresAuth) {
        const account = authService.getAccount();
        if (!account) {
            await authService.login();
            const newAccount = authService.getAccount();
            if (newAccount) {
                next();
            } else {
                next('/login');
            }
        } else {
            next();
        }
    } else {
        next();
    }
});

export default router;
  

5.3. Integrate Router into Vue Application

Modify src/main.js to use the router:


import { createApp } from 'vue';
import App from './App.vue';
import router from './router';
import { PublicClientApplication } from '@azure/msal-browser';
import { msalConfig } from './auth/authConfig';

const msalInstance = new PublicClientApplication(msalConfig);

const app = createApp(App);

app.config.globalProperties.$msal = msalInstance;

app.use(router);
app.mount('#app');
  

Step 6: Handling Token Acquisition for API Calls

6.1. Acquire Access Tokens

To make authenticated API calls, you need to acquire access tokens. Use the authService created earlier to handle token acquisition:


async function fetchUserProfile() {
    const token = await authService.acquireToken();
    if (token) {
        try {
            const response = await fetch('https://graph.microsoft.com/v1.0/me', {
                headers: {
                    'Authorization': `Bearer ${token}`
                }
            });
            const data = await response.json();
            console.log('User Profile:', data);
        } catch (error) {
            console.error('Error fetching user profile:', error);
        }
    } else {
        console.error('No access token available.');
    }
}
  

6.2. Example: Fetching User Profile in Home Component

Modify Home.vue to fetch and display the user's profile:


<template>
  <div>
    <h1>Home</h1>
    <div v-if="userProfile">
      <p>Name: {{ userProfile.displayName }}</p>
      <p>Email: {{ userProfile.mail || userProfile.userPrincipalName }}</p>
    </div>
    <div v-else>
      <p>Loading user profile...</p>
    </div>
  </div>
</template>

<script>
import { ref, onMounted } from 'vue';
import { authService } from '../auth/authService';

export default {
    name: 'Home',
    setup() {
        const userProfile = ref(null);

        const fetchUserProfile = async () => {
            const token = await authService.acquireToken();
            if (token) {
                try {
                    const response = await fetch('https://graph.microsoft.com/v1.0/me', {
                        headers: {
                            'Authorization': `Bearer ${token}`
                        }
                    });
                    userProfile.value = await response.json();
                } catch (error) {
                    console.error('Error fetching user profile:', error);
                }
            }
        };

        onMounted(() => {
            fetchUserProfile();
        });

        return {
            userProfile
        };
    }
};
</script>
  

Step 7: Testing Your SSO Implementation

7.1. Run Your Vue.js Application

Start the development server to test your SSO integration:

npm run serve

7.2. Access the Application

Open your browser and navigate to http://localhost:8080. You should see the login button if you're not authenticated.

7.3. Authenticate Using Azure AD

  1. Click on the Login button.
  2. You will be redirected to the Azure AD login page. Enter your Azure credentials.
  3. Upon successful authentication, you should be redirected back to your Vue.js application.
  4. Access protected routes to ensure that authentication is enforced.
  5. Verify that access tokens are acquired successfully for API calls.

7.4. Handle Possible Issues

If you encounter issues during authentication, consider the following troubleshooting steps:

  • Ensure that the Client ID and Tenant ID are correctly configured in authConfig.js.
  • Verify that the Redirect URI in Azure AD matches the one in your Vue.js application.
  • Check browser console logs for any error messages related to authentication.
  • Ensure that necessary API permissions are granted and admin consent is provided if required.

Conclusion

Implementing Single Sign-On (SSO) using Azure Active Directory in a Vue.js application enhances security and provides a seamless authentication experience for users. By following the steps outlined in this guide, you can integrate Azure AD authentication effectively, manage user sessions securely, and protect routes within your application. Ensure to keep your dependencies updated and monitor authentication flows to maintain a robust and secure application.


References


This guide provides a comprehensive approach to implementing Single Sign-On (SSO) using Azure Active Directory in a Vue.js application. By following these steps, you can ensure secure authentication flows, protect sensitive routes, and provide a seamless user experience.


Last updated January 19, 2025
Ask Ithy AI
Download Article
Delete Article