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.

Error when attempting to use `InteractiveBrowserCredential` for downloading from blob storage

See original GitHub issue
  • Package Name: @azure/identity
  • Package Version: 2.0.0-beta.6
  • Package Name: @azure/storage-blob
  • Package Version: ^12.11.0
  • Operating system: OSX
  • nodejs
    • version: ^13.7.0
  • browser
    • name/version:
  • typescript
    • version: ~4.6.2
  • Is the bug related to documentation in

Describe the bug We’re seeing the following error in the terminal when we attempt to use the InteractiveBrowserCredential class to authorize a script to download files from blob storage for the user.

Error: Interactive Browser Authentication Error “Did not receive token with a valid expiration”

At the same time, we see this error in the browser which opens for the interactive authentication:

ERROR. Scopes: https://storage.azure.com/.default. Error message: null. null.

A simplified example of the code that is producing this error would be the following function that downloads a blob to a given directory then returns the path to that directory as a string:

export async function downloadOurSdk(version: string, downloadDirectory: string): Promise<string> {
  const credential = new InteractiveBrowserCredential({
    tenantId: '<redacted>',
    clientId: '<redacted>',
    loginStyle: 'redirect',
    redirectUri: 'http://localhost:8080/',
  });
  const blobServiceClient = new BlobServiceClient('https://<redacted>.blob.core.windows.net', credential);

  const containerClient = blobServiceClient.getContainerClient(version);
  const blockBlobClient = containerClient.getBlockBlobClient('our-sdk.zip');

  await blockBlobClient.downloadToFile(downloadDirectory, 0, undefined);
  console.log('\nDownloaded blob content...');

  return downloadDirectory;
}

The error appears to be thrown by the call to await blockBlobClient.donwloadToFile(downloadDirectory, 0, undefined); because the console.log after that line is never seen in the terminal (while a console.log placed directly before that line is printed to the terminal).

I haven’t been able to find much of anything about this error online, so I’ve been reading all the documentation about the InteractiveBrowserCredential class, the InteractiveBrowserCredentialNodeOptions interface, the BlockBlobClient class’s downloadToFile method, and the BlobDownloadOptions interface, but I don’t see any mention of an expiration or timeout property in any of them (though that may be a red herring).

I’m not really sure what steps to take next, and I was hoping y’all might be able to catch something obvious that I missed about this. Note that I have also followed the instructions here to enable verbose logging, and I’ve attached the output of that at the end of this issue.

Thanks for any assistance you can give!

To Reproduce Steps to reproduce the behavior:

  1. Use an InteractiveBrowserCredential to acquire a BlobServiceClient (using the @azure/storage-blob package).
  2. Use the BlobServiceClient to obtain a ContainerClient.
  3. Use the ContainerClient to obtain a BlockBlobClient.
  4. Call the BlockBlobClient’s downloadToFile method.

Expected behavior The Microsoft credentials used to login with the InteractiveBrowserCredential should be used to authorize downloading the given blob to a file in the given directory.

Screenshots n/a

Additional context --verbose logs from the given error:

azure:core-client:warning The baseUri option for SDK Clients has been deprecated, please use endpoint instead.
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: {
  "streamResponseStatusCodes": {},
  "url": "https://harborsdkbinaries.blob.core.windows.net/2-8-1-18-74105c96-osx/harbor-sdk.zip",
  "method": "GET",
  "headers": {
    "_headersMap": {
      "x-ms-version": "2021-08-06",
      "accept": "application/xml",
      "user-agent": "azsdk-js-storageblob/12.11.0 (NODE-VERSION v18.2.0; Darwin 21.6.0)",
      "x-ms-client-request-id": "cb0f50e4-ee40-4eda-9639-67c58b069179"
    }
  },
  "withCredentials": false,
  "timeout": 0,
  "keepAlive": true,
  "requestId": "cb0f50e4-ee40-4eda-9639-67c58b069179"
}
azure:identity:info InteractiveBrowserCredential => MSAL Node V2 info message: [Thu, 25 Aug 2022 18:58:15 GMT] : @azure/msal-node@1.12.1 : Info - getTokenCache called
azure:identity:info Node.js MSAL Open Browser => More than one account was found authenticated for this Client ID and Tenant ID.
However, no "authenticationRecord" has been provided for this credential,
therefore we're unable to pick between these accounts.
A new login attempt will be requested, to ensure the correct account is picked.
To work with multiple accounts for the same Client ID and Tenant ID, please provide an "authenticationRecord" when initializing a credential to prevent this from happening.
azure:identity:info Node.js MSAL Open Browser => Silent authentication failed, falling back to interactive method.
azure:identity:info Node.js MSAL Open Browser => InteractiveBrowserCredential listening on port 8080!
azure:identity:info InteractiveBrowserCredential => MSAL Node V2 info message: [Thu, 25 Aug 2022 18:58:15 GMT] : @azure/msal-node@1.12.1 : Info - getAuthCodeUrl called
azure:core-rest-pipeline retryPolicy:info Retry 0: Attempting to send request 36fae5c9-01d4-4ae2-9ada-08d611d802f9
azure:core-rest-pipeline:info Request: {
  "url": "https://login.microsoftonline.com/common/discovery/instance?api-version=1.1&authorization_endpoint=REDACTED",
  "headers": {
    "accept-encoding": "gzip,deflate",
    "user-agent": "azsdk-js-identity/2.0.0-beta.6 core-rest-pipeline/1.9.1 Node/v18.2.0 OS/(x64-Darwin-21.6.0)",
    "x-ms-client-request-id": "36fae5c9-01d4-4ae2-9ada-08d611d802f9"
  },
  "method": "GET",
  "timeout": 0,
  "disableKeepAlive": false,
  "withCredentials": false,
  "abortSignal": {},
  "requestId": "36fae5c9-01d4-4ae2-9ada-08d611d802f9",
  "allowInsecureConnection": false,
  "enableBrowserStreams": false
}
azure:core-rest-pipeline:info No cached TLS Agent exist, creating a new Agent
azure:core-rest-pipeline:info Response status code: 200
azure:core-rest-pipeline:info Headers: {
  "cache-control": "max-age=86400, private",
  "content-type": "application/json; charset=utf-8",
  "strict-transport-security": "max-age=31536000; includeSubDomains",
  "x-content-type-options": "nosniff",
  "access-control-allow-origin": "*",
  "access-control-allow-methods": "GET, OPTIONS",
  "p3p": "CP=\"DSP CUR OTPi IND OTRi ONL FIN\"",
  "x-ms-request-id": "ed593fac-641e-4e4b-bf2c-696cf8f29000",
  "x-ms-ests-server": "2.1.13481.11 - SCUS ProdSlices",
  "x-xss-protection": "0",
  "set-cookie": "fpc=Aq-ZappgSQpPmzILacS8OEI; expires=Sat, 24-Sep-2022 18:58:16 GMT; path=/; secure; HttpOnly; SameSite=None",
  "date": "Thu, 25 Aug 2022 18:58:16 GMT",
  "content-length": "980"
}
azure:core-rest-pipeline retryPolicy:info Retry 0: Received a response from request 36fae5c9-01d4-4ae2-9ada-08d611d802f9
azure:core-rest-pipeline retryPolicy:info Retry 0: Processing 2 retry strategies.
azure:core-rest-pipeline retryPolicy:info Retry 0: Processing retry strategy throttlingRetryStrategy.
azure:core-rest-pipeline retryPolicy:info Retry 0: Skipped.
azure:core-rest-pipeline retryPolicy:info Retry 0: Processing retry strategy exponentialRetryStrategy.
azure:core-rest-pipeline retryPolicy:info Retry 0: Skipped.
azure:core-rest-pipeline retryPolicy:info None of the retry strategies could work with the received response. Returning it.
azure:core-rest-pipeline retryPolicy:info Retry 0: Attempting to send request 927305c4-23e9-4b13-af1b-661045c0b274
azure:core-rest-pipeline:info Request: {
  "url": "https://login.microsoftonline.com/72f988bf-86f1-41af-91ab-2d7cd011db47/v2.0/.well-known/openid-configuration",
  "headers": {
    "accept-encoding": "gzip,deflate",
    "user-agent": "azsdk-js-identity/2.0.0-beta.6 core-rest-pipeline/1.9.1 Node/v18.2.0 OS/(x64-Darwin-21.6.0)",
    "x-ms-client-request-id": "927305c4-23e9-4b13-af1b-661045c0b274"
  },
  "method": "GET",
  "timeout": 0,
  "disableKeepAlive": false,
  "withCredentials": false,
  "abortSignal": {},
  "requestId": "927305c4-23e9-4b13-af1b-661045c0b274",
  "allowInsecureConnection": false,
  "enableBrowserStreams": false
}
azure:core-rest-pipeline:info Response status code: 200
azure:core-rest-pipeline:info Headers: {
  "cache-control": "max-age=86400, private",
  "content-type": "application/json; charset=utf-8",
  "strict-transport-security": "max-age=31536000; includeSubDomains",
  "x-content-type-options": "nosniff",
  "access-control-allow-origin": "*",
  "access-control-allow-methods": "GET, OPTIONS",
  "p3p": "CP=\"DSP CUR OTPi IND OTRi ONL FIN\"",
  "x-ms-request-id": "27228cfa-649f-4a09-9007-6d20fffd4200",
  "x-ms-ests-server": "2.1.13481.12 - SCUS ProdSlices",
  "x-xss-protection": "0",
  "set-cookie": "fpc=AnGD6erPafxDm5xhJ2FGGQU; expires=Sat, 24-Sep-2022 18:58:16 GMT; path=/; secure; HttpOnly; SameSite=None",
  "date": "Thu, 25 Aug 2022 18:58:16 GMT",
  "content-length": "1753"
}
azure:core-rest-pipeline retryPolicy:info Retry 0: Received a response from request 927305c4-23e9-4b13-af1b-661045c0b274
azure:core-rest-pipeline retryPolicy:info Retry 0: Processing 2 retry strategies.
azure:core-rest-pipeline retryPolicy:info Retry 0: Processing retry strategy throttlingRetryStrategy.
azure:core-rest-pipeline retryPolicy:info Retry 0: Skipped.
azure:core-rest-pipeline retryPolicy:info Retry 0: Processing retry strategy exponentialRetryStrategy.
azure:core-rest-pipeline retryPolicy:info Retry 0: Skipped.
azure:core-rest-pipeline retryPolicy:info None of the retry strategies could work with the received response. Returning it.
azure:identity:info InteractiveBrowserCredential => MSAL Node V2 info message: [Thu, 25 Aug 2022 18:58:17 GMT] : @azure/msal-node@1.12.1 : Info - acquireTokenByCode called
azure:identity:info InteractiveBrowserCredential => MSAL Node V2 info message: [Thu, 25 Aug 2022 18:58:17 GMT] : [6171d1d6-3c74-455c-8364-a9078fea62b7] : @azure/msal-common@7.3.0 : Info - in acquireToken call
azure:core-rest-pipeline retryPolicy:info Retry 0: Attempting to send request e3d911d9-0c4f-43a4-acac-19f5ffca512a
azure:core-rest-pipeline:info Request: {
  "url": "https://login.microsoftonline.com/72f988bf-86f1-41af-91ab-2d7cd011db47/oauth2/v2.0/token",
  "headers": {
    "content-type": "application/x-www-form-urlencoded;charset=utf-8",
    "accept-encoding": "gzip,deflate",
    "user-agent": "azsdk-js-identity/2.0.0-beta.6 core-rest-pipeline/1.9.1 Node/v18.2.0 OS/(x64-Darwin-21.6.0)",
    "x-ms-client-request-id": "e3d911d9-0c4f-43a4-acac-19f5ffca512a"
  },
  "method": "POST",
  "timeout": 0,
  "disableKeepAlive": false,
  "withCredentials": false,
  "abortSignal": {},
  "requestId": "e3d911d9-0c4f-43a4-acac-19f5ffca512a",
  "allowInsecureConnection": false,
  "enableBrowserStreams": false
}
azure:core-rest-pipeline:info Response status code: 400
azure:core-rest-pipeline:info Headers: {
  "cache-control": "no-store, no-cache",
  "pragma": "no-cache",
  "content-type": "application/json; charset=utf-8",
  "expires": "-1",
  "strict-transport-security": "max-age=31536000; includeSubDomains",
  "x-content-type-options": "nosniff",
  "p3p": "CP=\"DSP CUR OTPi IND OTRi ONL FIN\"",
  "x-ms-request-id": "48444501-1d77-4280-ae65-7c5b5c130100",
  "x-ms-ests-server": "2.1.13672.0 - CHY FirstSlice",
  "x-ms-clitelem": "1,9002327,0,,I",
  "x-xss-protection": "0",
  "set-cookie": "fpc=Ah_S4yGIGwVDn7N-J4rczGaYKMIdAQAAAEm9mdoOAAAA; expires=Sat, 24-Sep-2022 18:58:18 GMT; path=/; secure; HttpOnly; SameSite=None",
  "date": "Thu, 25 Aug 2022 18:58:18 GMT",
  "content-length": "478"
}
azure:core-rest-pipeline retryPolicy:info Retry 0: Received a response from request e3d911d9-0c4f-43a4-acac-19f5ffca512a
azure:core-rest-pipeline retryPolicy:info Retry 0: Processing 2 retry strategies.
azure:core-rest-pipeline retryPolicy:info Retry 0: Processing retry strategy throttlingRetryStrategy.
azure:core-rest-pipeline retryPolicy:info Retry 0: Skipped.
azure:core-rest-pipeline retryPolicy:info Retry 0: Processing retry strategy exponentialRetryStrategy.
azure:core-rest-pipeline retryPolicy:info Retry 0: Skipped.
azure:core-rest-pipeline retryPolicy:info None of the retry strategies could work with the received response. Returning it.
azure:identity:info Node.js MSAL Open Browser => getToken() => ERROR. Scopes: https://storage.azure.com/.default. Error message: null. null.
azure:storage-blob:error RetryPolicy: Caught error, message: Interactive Browser Authentication Error "Did not receive token with a valid expiration", code: undefined
harbor-install Invocation Failed:
Error: Interactive Browser Authentication Error "Did not receive token with a valid expiration"
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.

Issue Analytics

  • State:closed
  • Created a year ago
  • Comments:11 (5 by maintainers)

github_iconTop GitHub Comments

1reaction
xirzeccommented, Aug 30, 2022

Ah I think I see the shape of this a bit better. Am I correct in understanding you are building a command-line tool that can download a blob using the user’s credentials?

DefaultAzureCredential is magical when it works, though it does require some form of active identity present on the machine. Managed Identity is more about authenticating a deployed service without extra configuration than it is about authenticating a local user against AAD, so I’m not sure how useful it will be if I understand your use-case.

Until WAM is supported, you’re probably right that InteractiveBrowserCredential is the “correct” flow for your use case, though the app registration bits make it complex. @schaabs do you have any advice here?

1reaction
xirzeccommented, Aug 26, 2022

I spent a bit of time trying to repro this so I could debug it, but I can’t seem to get past this blocker:

image

Whenever I have my app request user_impersonation of storage it claims it needs admin consent… even though I can’t see any reason why it should. Using other kinds of AAD auth (e.g. EnvironmentCredential with that same app using a secret) works great.

Read more comments on GitHub >

github_iconTop Results From Across the Web

azure.identity.InteractiveBrowserCredential class
Authenticates as a service principal using a certificate. The certificate must have an RSA private key, because this credential signs assertions using RS256....
Read more >
python 3.x - Unable to connect to azure blob storage using ...
To use InteractiveBrowserCredential, you need to add a redirect url under Mobile and desktop applications platform, not web platform.
Read more >
[Example code]-Unable to connect to azure blob storage using ...
This code works just fine: from azure.storage.blob import BlobServiceClient from azure.identity import InteractiveBrowserCredential, DeviceCodeCredential, ...
Read more >
Azure Identity client library for .NET
This example demonstrates authenticating the BlobClient from the Azure.Storage.Blobs client library using the InteractiveBrowserCredential . using Azure.
Read more >
Connecting to Azure blob storage from React using Azure ...
This works for upload too - standard storage in the US has a max ingress of 10Gb/s. Clients uploading or downloading directory to...
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