question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Acquiring new Azure AD access token for every request instead reusing the access token till it's validity time

See original GitHub issue
  • Package Name: @azure/storage-blob, @azure/identity
  • Package Version: 12.3.0, 1.2.0
  • Operating system: Windows 10
  • nodejs
    • version: v10.16.3
  • browser
    • name/version:
  • typescript
    • version: v1.5.3
  • Is the bug related to documentation in

Describe the bug A clear and concise description of what the bug is. We are using ClientSecretCredential for Azure AD authentication for Azure Blob service. As per our observation based on the logging the Azure Blob Javascript SDK is not reusing the Azure AD access token generated for immediate requests instead it is generating fresh token for every request.

To Reproduce Steps to reproduce the behavior:

  1. Use the below provided sample code and run the program using NodeJS command. Access the program from browser using URL http://localhost:3022/, you can see acquiring the Azure AD access token which is valid for one hour.

const express = require('express')
const app = express()
const { BlobServiceClient } = require('@azure/storage-blob')
const { ClientSecretCredential } = require('@azure/identity')
const logger = require('@azure/logger')
app.get('/', (req, res) => {
  try {
    logger.setLogLevel('verbose')
    const account = '<<teststorageaccount>>'
    const clientSecretCredential = new ClientSecretCredential('<<TenantId>>', '<<ClientId>>', '<<ClientSecret>>')
    const containerName = '<<testcontainer>>'
    const blobName = 'test_blob.txt'
    const blobServiceClient = new BlobServiceClient(
      `https://${account}.blob.core.windows.net`,
      clientSecretCredential
    )
    const containerClient = blobServiceClient.getContainerClient(containerName)
    const blockBlobClient = containerClient.getBlockBlobClient(blobName)
    const downloadBlobResponse = blockBlobClient.download(0)
    downloadBlobResponse.then(function convertStream2Buffer(downloadBlobResponse) {
        const fileContent = streamToBuffer(downloadBlobResponse.readableStreamBody)
        fileContent.then((data) => {
          console.log(`Downloaded Blob Response for '${blobName}' data.length bytes is :::  `, data.length)
          console.log('$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$')
          res.send('SSSUUUUCCCCCEEEEEEEESSSSSSSS!!!!!!!!!!  data.length bytes #####  ' + data.length)
        })
      }
    )    
  } catch (err) {
    console.log('EEEEEEEEEEERRRRRRRRRRRRRRROOOOOOOOOOOOORRRRRRRRRRRRR  : ', err)
  }
})

function streamToBuffer (readableStream) {
  return new Promise((resolve, reject) => {
    const chunks = []
    readableStream.on('data', (data) => {
      chunks.push(data instanceof Buffer ? data : Buffer.from(data))
    })
    readableStream.on('end', () => {
      resolve(Buffer.concat(chunks))
    })
    readableStream.on('error', reject)
  })
}

app.listen(3022, function () {
  console.log('app listening on port 3022!')
})


Logs from the first execution where it shows acquiring access token which is valid for one hour.

D:\AzureBlob> node BlobClient_verify_token_generation.js
app listening on port 3022!
azure:core-http:info ServiceClient: using custom request policies
azure:core-http:info ServiceClient: using custom request policies
azure:core-http:info ServiceClient: using custom request policies
azure:core-http:info ServiceClient: using custom request policies
azure:storage-blob:info RetryPolicy: =====> Try=1 Primary        
azure:storage-blob:info Request: {
  "streamResponseBody": true,
  "url": "https://<<teststorageaccount>>.blob.core.windows.net/<<testcontainer>>/test_blob.txt",
  "method": "GET",
  "headers": {
    "_headersMap": {
      "x-ms-version": "2020-04-08",
      "user-agent": "azsdk-js-storageblob/12.4.0 (NODE-VERSION v10.16.3; Windows_NT 10.0.19041)",
      "x-ms-client-request-id": "002dd0b-36cd-4700-b0d6-c01e0f99dcd"
    }
  },
  "withCredentials": false,
  "timeout": 0,
  "keepAlive": true,
  "requestId": "002dd0b-36cd-4700-b0d6-c01e0f99dcd"
}
azure:identity:info IdentityClient: sending token request to [https://login.microsoftonline.com/<<TenantId>>/oauth2/v2.0/token]
azure:core-http:info Request: {
  "url": "https://login.microsoftonline.com/<<TenantId>>/oauth2/v2.0/token",
  "method": "POST",
  "headers": {
    "_headersMap": {
      "accept": "application/json",
      "content-type": "application/x-www-form-urlencoded",
      "accept-language": "REDACTED",
      "x-ms-client-request-id": "7d873f-f571-4c7c-be1e-17b29b2d81",
      "user-agent": "core-http/1.2.1 Node/v10.16.3 OS/(x64-Windows_NT-10.0.19041)"
    }
  },
  "withCredentials": false,
  "timeout": 0,
  "keepAlive": true,
  "requestId": "7d873f-f571-4c7c-be1e-17b29b2d81"
}
azure:core-http:info Response status code: 200
azure:core-http:info Headers: {
  "_headersMap": {
    "cache-control": "no-store, no-cache",
    "content-length": "1316",
    "content-type": "application/json; charset=utf-8",
    "date": "Mon, 25 Jan 2021 07:56:48 GMT",
    "expires": "-1",
    "p3p": "REDACTED",
    "pragma": "no-cache",
    "set-cookie": "REDACTED",
    "strict-transport-security": "REDACTED",
    "x-content-type-options": "REDACTED",
    "x-ms-ests-server": "REDACTED",
    "x-ms-request-id": "58486a-756e-4af3-bca-9dd52435100"
  }
}
azure:identity:info IdentityClient: [https://login.microsoftonline.com/<<TenantId>>/oauth2/v2.0/token] token acquired, expires on 1611565008171
azure:identity:info ClientSecretCredential => getToken() => SUCCESS. Scopes: https://storage.azure.com/.default.
azure:storage-blob:info Response status code: 200
azure:storage-blob:info Headers: {
  "_headersMap": {
    "accept-ranges": "bytes",
    "access-control-allow-origin": "*",
    "access-control-expose-headers": "x-ms-request-id,x-ms-client-request-id,Server,x-ms-version,x-ms-version-id,x-ms-is-current-version,Content-Type,Last-Modified,ETag,x-ms-creation-time,Content-MD5,x-ms-lease-status,x-ms-lease-state,x-ms-blob-type,x-ms-server-encrypted,Accept-Ranges,Content-Length,Date,Transfer-Encoding",
    "content-length": "11",
    "content-md5": "sQqNsWTgdUEFddft6mb5y4/5Q==",
    "content-type": "application/octet-stream",
    "date": "Mon, 25 Jan 2021 07:56:49 GMT",
    "etag": "\"0x8DG8BD42dwB018D3E5C1\"",
    "last-modified": "Wed, 20 Jan 2021 12:55:39 GMT",
    "server": "Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0",
    "x-ms-blob-type": "BlockBlob",
    "x-ms-client-request-id": "002sddd0b-36cd-4700-b0d6-c01we0f99dcd",
    "x-ms-creation-time": "Wed, 20 Jan 2021 12:55:39 GMT",
    "x-ms-is-current-version": "REDACTED",
    "x-ms-lease-state": "available",
    "x-ms-lease-status": "unlocked",
    "x-ms-request-id": "38f8csd972-001e-006e-6ewef-f2f912s000000",
    "x-ms-server-encrypted": "true",
    "x-ms-version": "2020-04-08",
    "x-ms-version-id": "REDACTED"
  }
}
Downloaded Blob Response for 'test_blob.txt' data.length bytes is :::   11
$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$

  1. Refresh the browser and you can again see the logs for acquiring the new Azure AD access token with one hour validity. Below is the logs for the 2nd execution.

azure:core-http:info ServiceClient: using custom request policies
azure:core-http:info ServiceClient: using custom request policies
azure:core-http:info ServiceClient: using custom request policies
azure:core-http:info ServiceClient: using custom request policies
azure:storage-blob:info RetryPolicy: =====> Try=1 Primary
azure:storage-blob:info Request: {
  "streamResponseBody": true,
  "url": "https://<<teststorageaccount>>.blob.core.windows.net/<<testcontainer>>/test_blob.txt",
  "method": "GET",
  "headers": {
    "_headersMap": {
      "x-ms-version": "2020-04-08",
      "user-agent": "azsdk-js-storageblob/12.4.0 (NODE-VERSION v10.16.3; Windows_NT 10.0.19041)",
      "x-ms-client-request-id": "547dwe3314c-ae12-41eeb-9a4a-a036dewc7c0a"
    }
  },
  "withCredentials": false,
  "timeout": 0,
  "keepAlive": true,
  "requestId": "547dwe3314c-ae12-41eeb-9a4a-a036dewc7c0a"
}
azure:identity:info IdentityClient: sending token request to [https://login.microsoftonline.com/<<TenantId>>/oauth2/v2.0/token]
azure:core-http:info Request: {
  "url": "https://login.microsoftonline.com/<<TenantId>>/oauth2/v2.0/token",
  "method": "POST",
  "headers": {
    "_headersMap": {
      "accept": "application/json",
      "content-type": "application/x-www-form-urlencoded",
      "accept-language": "REDACTED",
      "x-ms-client-request-id": "38eefa81-26c7-4fa4-8we7-b486ds929b47",
      "user-agent": "core-http/1.2.1 Node/v10.16.3 OS/(x64-Windows_NT-10.0.19041)"
    }
  },
  "withCredentials": false,
  "timeout": 0,
  "keepAlive": true,
  "requestId": "38eefa81-26c7-4fa4-8we7-b486ds929b47"
}
azure:core-http:info Response status code: 200
azure:core-http:info Headers: {
  "_headersMap": {
    "cache-control": "no-store, no-cache",
    "content-length": "1316",
    "content-type": "application/json; charset=utf-8",
    "date": "Mon, 25 Jan 2021 07:56:54 GMT",
    "expires": "-1",
    "p3p": "REDACTED",
    "pragma": "no-cache",
    "set-cookie": "REDACTED",
    "strict-transport-security": "REDACTED",
    "x-content-type-options": "REDACTED",
    "x-ms-ests-server": "REDACTED",
    "x-ms-request-id": "80bsdwd4-a473-4994-94wew-6sdc28dwew5800"
  }
}
azure:identity:info IdentityClient: [https://login.microsoftonline.com/<<TenantId>>/oauth2/v2.0/token] token acquired, expires on 1611565013531
azure:identity:info ClientSecretCredential => getToken() => SUCCESS. Scopes: https://storage.azure.com/.default.
azure:storage-blob:info Response status code: 200
azure:storage-blob:info Headers: {
  "_headersMap": {
    "accept-ranges": "bytes",
    "access-control-allow-origin": "*",
    "access-control-expose-headers": "x-ms-request-id,x-ms-client-request-id,Server,x-ms-version,x-ms-version-id,x-ms-is-current-version,Content-Type,Last-Modified,ETag,x-ms-creation-time,Content-MD5,x-ms-lease-status,x-ms-lease-state,x-ms-blob-type,x-ms-server-encrypted,Accept-Ranges,Content-Length,Date,Transfer-Encoding",
    "content-length": "11",
    "content-md5": "sQqNsWTgdUEFddft6mb5y4/5Q==",
    "content-type": "application/octet-stream",
    "date": "Mon, 25 Jan 2021 07:56:54 GMT",
    "etag": "\"0x8DG8BD42dwB018D3E5C1\"",
    "last-modified": "Wed, 20 Jan 2021 12:55:39 GMT",
    "server": "Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0",
    "x-ms-blob-type": "BlockBlob",
    "x-ms-client-request-id": "547dwe3314c-ae12-41eeb-9a4a-a036dewc7c0a",
    "x-ms-creation-time": "Wed, 20 Jan 2021 12:55:39 GMT",
    "x-ms-is-current-version": "REDACTED",
    "x-ms-lease-state": "available",
    "x-ms-lease-status": "unlocked",
    "x-ms-request-id": "38sdwed-001e-00sdw6e-6def-f2sdwe2000000",
    "x-ms-server-encrypted": "true",
    "x-ms-version": "2020-04-08",
    "x-ms-version-id": "REDACTED"
  }
}
Downloaded Blob Response for 'test_blob.txt' data.length bytes is :::   11
$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$

Expected behavior A clear and concise description of what you expected to happen.

The subsequent API calls through Azure AD authentication should use the Azure AD access token till it’s validity ends and the SDK should re-generate the access token on it’s expire. In this case the access token generation should be for every one hour considering we are running it as web application.

Screenshots If applicable, add screenshots to help explain your problem.

Additional context Add any other context about the problem here.

We have app registration created and Storage Blob Data Contributor role assigned. The access to Azure Blob is working without any issue. Only concern is on new token generation for every request.

If the SDK is designed to work in that way is there any limit on the maximum number of tokens generated per account?

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Comments:18 (12 by maintainers)

github_iconTop GitHub Comments

1reaction
sadasantcommented, Mar 1, 2021

@prashanthmadduri We merged the PR that fixes the issue you saw. We will release this change this week. I will come back with more information by the end of the week.

1reaction
prashanthmadduricommented, Feb 26, 2021

@sadasant thank you for update. We will try with final public release with this fix.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Microsoft identity platform access tokens
When issued, the default lifetime of an access token is assigned a random value ranging between 60-90 minutes (75 minutes on average). The ......
Read more >
Configurable token lifetimes - Microsoft Entra
ID tokens are considered valid until their expiry. Usually, a web application matches a user's session lifetime in the application to the ...
Read more >
Microsoft identity platform refresh tokens
Refresh token lifetime ... Refresh tokens have a longer lifetime than access tokens. The default lifetime for the refresh tokens is 24 hours...
Read more >
Refresh the access token in Power BI embedded analytics
Learn how to renew or refresh the access token so users will get continuous experience and avoid the token being expired.
Read more >
Configure tokens - Azure Active Directory B2C - Microsoft Learn
Refresh token lifetime (days) - The maximum time period before which a refresh token can be used to acquire a new access token, ......
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found