Back

How to build a public Azure DevOps integration: Building the Auth Flow

Aug 2, 20247 minute read

Hey there, fellow JavaScript developer! Ready to dive into the world of Azure DevOps integrations? Today, we're going to tackle one of the most crucial aspects of building a public integration: the authorization flow. Don't worry, it's not as daunting as it sounds. By the end of this article, you'll have a solid grasp on implementing a secure and user-friendly auth flow for your Azure DevOps integration.

Prerequisites

Before we jump in, make sure you've got:

  • An Azure DevOps account (if you don't have one, go grab one – it's free!)
  • A registered application in Azure AD (trust me, it's easier than it sounds)

Got those? Great! Let's get started.

OAuth 2.0 Authorization Code Flow: Your New Best Friend

When it comes to user-facing integrations, the OAuth 2.0 Authorization Code Flow is your go-to solution. It's secure, it's user-friendly, and it's perfect for our needs. Here's why:

  1. It's designed for web applications
  2. It provides a way to get both access and refresh tokens
  3. It keeps your users' credentials safe by never exposing them to your application

Sounds good, right? Let's see how to implement it.

Implementing the Authorization Flow

Step 1: Initiating the auth request

First things first, we need to send our users to Azure AD to authenticate. Here's how:

const authUrl = 'https://app.vssps.visualstudio.com/oauth2/authorize'; const clientId = 'YOUR_CLIENT_ID'; const redirectUri = 'YOUR_REDIRECT_URI'; const scope = 'vso.work'; const fullAuthUrl = `${authUrl}?client_id=${clientId}&response_type=code&redirect_uri=${encodeURIComponent(redirectUri)}&scope=${encodeURIComponent(scope)}`; // Redirect the user to fullAuthUrl

Step 2: Handling the callback

After the user authenticates, Azure AD will redirect them back to your redirectUri with an authorization code. Let's grab it:

const urlParams = new URLSearchParams(window.location.search); const code = urlParams.get('code'); if (code) { // We've got the code! Time to exchange it for tokens } else { // Uh-oh, something went wrong. Handle the error. }

Step 3: Exchanging the code for tokens

Now that we have the code, let's swap it for some shiny new tokens:

const tokenUrl = 'https://app.vssps.visualstudio.com/oauth2/token'; const response = await fetch(tokenUrl, { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: new URLSearchParams({ client_id: 'YOUR_CLIENT_ID', client_secret: 'YOUR_CLIENT_SECRET', code, redirect_uri: 'YOUR_REDIRECT_URI', grant_type: 'authorization_code' }) }); const { access_token, refresh_token } = await response.json();

Step 4: Storing and refreshing tokens

Great job! You've got your tokens. Now, let's keep them safe and fresh:

// Store tokens securely (please use a more secure method in production!) localStorage.setItem('accessToken', access_token); localStorage.setItem('refreshToken', refresh_token); // Refresh token when needed async function refreshAccessToken() { const response = await fetch(tokenUrl, { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: new URLSearchParams({ client_id: 'YOUR_CLIENT_ID', client_secret: 'YOUR_CLIENT_SECRET', refresh_token: localStorage.getItem('refreshToken'), grant_type: 'refresh_token' }) }); const { access_token, refresh_token } = await response.json(); localStorage.setItem('accessToken', access_token); localStorage.setItem('refreshToken', refresh_token); }

Making authenticated requests

Now that you've got your access token, you're ready to make some API calls:

async function getWorkItems() { const response = await fetch('https://dev.azure.com/{organization}/{project}/_apis/wit/workitems?api-version=6.0', { headers: { 'Authorization': `Bearer ${localStorage.getItem('accessToken')}` } }); if (response.status === 401) { await refreshAccessToken(); return getWorkItems(); // Retry the request } return response.json(); }

Best practices

Remember to always:

  1. Use HTTPS for all requests
  2. Validate all input and handle errors gracefully
  3. Implement proper token storage and refresh mechanisms
  4. Be mindful of rate limits and implement appropriate retry logic

Wrapping up

And there you have it! You've successfully implemented the authorization flow for your Azure DevOps integration. Pat yourself on the back – you've tackled one of the trickiest parts of building an integration.

From here, the sky's the limit. You can start building out more features, interacting with different parts of the Azure DevOps API, and creating an awesome integration that your users will love.

Remember, the key to a great integration is a smooth user experience and rock-solid security. Keep those in mind as you continue to build and improve your integration.

Happy coding, and may your builds always be green!

Additional resources

Want to dive deeper? Check out these resources: