Search code examples
azure-devopsazure-devops-rest-api

Azure DevOps PAT Authentication Issue - 403/203 Errors


I’m working with Azure DevOps and using a Global FULL Personal Access Token (PAT) across multiple organizations. This PAT is integrated into several Azure-hosted workflows to perform various API requests.

Problem: I’ve noticed that if I don’t log into the associated account via a browser for a certain period (sometimes as short as a day), I start receiving 403 or 203 errors when the workflows try to perform API requests on Azure DevOps. Interestingly, once I log into the account through the browser, the workflows resume normal operation without any errors.

What I’ve tried: So far, I’ve been manually logging into the account through the browser to resolve the issue, but this is not a sustainable solution.

Expected Outcome: I’m looking for a way to prevent these errors from occurring, even if I don’t log into the account via a browser for extended periods.

Any insights or suggestions would be greatly appreciated. Thank you!


Solution

  • For organizations backed by Microsoft Entra ID, you have 90 days to sign in with your new PAT, otherwise it's considered inactive. Besides, you can check whether you have enabled Sign-in frequency policy in your Microsoft Entra ID.

    In addition to using a PAT, you can use a service principal to call REST API via a Microsoft Entra token. You don't need to rotate it like a PAT, which must be laboriously rotated every so often (minimum 180 days). Besides, Microsoft Entra tokens expire every hour and must be regenerated with a refresh token to get a new access token, which limits the overall risk factor when leaked.

    1. Create an application service principal in Azure portal. enter image description here
    2. Add the service principal to each of your organizations and assign it with a license and specific permissions.
    3. Acquiring an access token for the service principal and use this token to access Azure DevOps resources. There is a PowerShell example for your reference.
    $tenantId = '{Tenant ID}'
    $clientId = '{Application (client) ID of your service principle} '
    $clientSecret = '{The secret value of your service principle}'
    $scope = "499b84ac-1321-427f-aa17-267ca6975798/.default"
    
    #Format web request body
    $body = @{
        'grant_type' = 'client_credentials'
        'client_id' = $clientId
        'client_secret' = $clientSecret
        'scope' = $scope
    }
    
    #Send request for OAuth authentication to receive token
    $Response = Invoke-RestMethod https://login.microsoftonline.com/$tenantId/oauth2/v2.0/token -ContentType 'application/x-www-form-urlencoded' -Method POST -Body $body
    
    # Format Auth token into useable header
    $accessHeader = @{
        'Authorization' = 'Bearer ' + $Response.access_token
        'Accept' = "application/json"
    }
    
    # Test connection/get project
    $requestUrl = "https://dev.azure.com/{Orgname}/_apis/projects/{Projectname}?api-version=7.1-preview.4"
    Invoke-RestMethod -uri $requestUrl -Method GET -Headers $accessHeader
    

    See the detailed info about using service principals to authenticate from Use service principals & managed identities.