Search code examples
azureoauthazure-storageazure-rest-apiazure-data-lake-gen2

OAuth token for REST API call to Azure Data Lake Storage Gen 2 using service principal


I'm working on an application (one of the core microservices) which will call the Azure ADLS Gen 2 to store files (in a filesystem) for further processing by other components.

I'm trying to obtain an OAuth token for the authentication purposes by calling Azure authentication endpoint using the preliminarily created service principal.

The PowerShell code I'm using to create a service principal:

Add-AzAccount -Subscription <SUBSCRIPTION ID>
$sp = New-AzADServicePrincipal -DisplayName <PRINCIPAL NAME>
Sleep 20
New-AzRoleAssignment -RoleDefinitionName Contributor -ServicePrincipalName $sp.ApplicationId
$sp.ApplicationId
$BSTR = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($sp.Secret)
$UnsecureSecret = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($BSTR)
$UnsecureSecret  

I'm using the values of $sp.ApplicationId as < Azure AD application client ID> and $UnsecureSecret as < Azure AD application client secret>.

The Azure AD application is then configured with API permissions:

enter image description here

I've added the Azure AD application as a STORAGE BLOB DATA CONTRIBUTOR to the storage account's IAM blade.

Next, I'm going yo obtain an OAuth token.
Below are the calls I've made using Postman:

GET

https://login.microsoftonline.com/<TENANT ID>/oauth2/token

Headers

Content-Type: application/x-www-form-urlencoded

Request body

grant_type:client_credentials
client_id: <Azure AD application client ID>
client_secret: <Azure AD application client secret>
scope: https://storage.azure.com/.default

After this call I'm able to get the successful response:

{
    "token_type": "Bearer",  
    "expires_in": "3600",  
    "ext_expires_in": "3600",  
    "expires_on": "1574686915",  
    "not_before": "1574683015",  
    "resource": "00000002-0000-0000-c000-000000000000",  
    "access_token": "eyJ0eX<..>" . 
}

Then I'm trying to create a filesystem by using the following request:

PUT

https://<STORAGE ACCOUNT NAME>.dfs.core.windows.net/<FILESYSTEM NAME>?resource=filesystem

Headers

Authorization: Bearer <JWT token>
x-ms-date: Mon, 25 Nov 2019 12:00:00 GMT
x-ms-version: 2019-02-02

And constantly getting the following error:

        {
            "error": {
                "code": "InvalidAuthenticationInfo",
                "message": "Server failed to authenticate the request.   
    Please refer to the information in the www-authenticate header.
\nRequestId:a6bf42d7-a01f-0006-1d88-a304da000000\nTime:2019-11-25T12:05:32.3049492Z"
            }
        }

I have tried different scopes but it doesn't help:

https://dfs.core.windows.net/.default
https://blob.core.windows.net/.default

Solution

  • I can reproduce your issue, the Contributor RBAC role is enough, no need to add any API permission, the issue was caused by the way you request the token, when using the v1.0 endpoint, you need to use resource: https://storage.azure.com/.

    GET https://login.microsoftonline.com/<TENANT ID>/oauth2/token
    
    grant_type:client_credentials
    client_id: <Azure AD application client ID>
    client_secret: <Azure AD application client secret>
    resource: https://storage.azure.com/
    

    Or you can change the request URL to v2.0 endpoint, it will also work.

    GET https://login.microsoftonline.com/<TENANT ID>/oauth2/v2.0/token
    
    grant_type:client_credentials
    client_id: <Azure AD application client ID>
    client_secret: <Azure AD application client secret>
    scope: https://storage.azure.com/.default
    

    Test:

    enter image description here