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
- README.md
- source code documentation
- SDK API docs on https://docs.microsoft.com
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:
- 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
$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
- 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:
- Created 3 years ago
- Comments:18 (12 by maintainers)
Top GitHub Comments
@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.
@sadasant thank you for update. We will try with final public release with this fix.