Introduction
In today’s post we’ll go through how you can setup an SPA (Single Page Application) to access the data pane of an Azure Storage account. For this I’ll be using NuxtJS (a Vue.js framework) for my boiler plating, and will rely on the its generic Oauth2 authentication library. The awesomeness here is that the bearer tokens will automatically be injected in your API calls (Axios). Though you can use this post as inspiration on how to get things working in another framework too!
Why this post? It has has been on my personal todo list for a while due to many reasons. One of which is to remove the barrier of using Azure Storage in this scenario. I find that it makes a lot of sense in way too many use cases. Though I must admit we’ve failed to reduce the learning curve in this scenario! You suddenly find yourself in flux between the complexities of AAD and the way how Azure Storage handles the presented JWT tokens. That being said, this is actually the only correct (secure) way of talking from an SPA to Azure Storage. DO NOT use storage keys or SAS tokens in your SPA. It’s like leaving your master keys out on the porch of your house. AAD is the correct way, and actually… With an SPA, the only correct authentication flow is actually Implicit Flow.
Sample Code Repository
If you are looking for the sample code used for this post ; https://github.com/kvaes/TasmanianTraders-NuxtJS-AzureStorageExample
Demo
“Now show me the cookie jar!” Okay okay… 😉 First of all, ensure that you have a storage account with an object inside of a container.
And that the needed permissions have been set!
If you are using the sample application, ensure that you’ve updated the secure.vue file to match that object.
And that the nuxt.js.config has the needed client_id set. After which you can launch the application…
Once booted up, you can reach the application at localhost:3000, where you browse to “Secure” ;
Here you’ll be prompted to do a login. Select “Login with AAD – Azure Storage scope” ;
Go through the typical AAD flow, and you’ll land on the Secure page. Press the “API Call”-button here.
And you’ll see that the “Response” & “token” fields get populated. The response will have the content of your blob object, where the token is the bearer token (JWT format).
Feel free to copy that one over (without “Bearer “)
And check it at “jwt.ms” ;
And you’ll see that the aud(ience = scope in Oauth 2.0) had been set to the one needed for storage. Now I can fully relate to you saying that the devil is in the details… So let’s take a look at the “Troubleshooting” chapter next! 😉
Important things to know (aka “Troubleshooting”)
The next items are a list of things I’ve encountered, where I can imagine that some of you will encounter them too… So here are some important things to know, so you can avoid the same headaches I’ve had! 😉
- Register your (AAD) application in the same tenant as to which your storage account has been deployed or you will get a “Issuer validation failed. Issuer did not match.”-error.
- Always use the AAD 2.0 endpoints for getting your tokens and set scope (audience) needs to be set to “https://storage.azure.com/user_impersonation” (“Signature validation failed.”)
- Include (correct) “x-ms-version” & (actual) “x-ms-date” in your header, or your message will not be accepted.
Or your message will not be accepted! (“Authentication scheme Bearer is not supported in this version.
And set it to “2017-07-28” (as minimum) ;
- Do not forget the CORS configuration
Closing Thoughts
In a SPA, do not expose any secrets in your code! This means that you should not put an account key into your code (like oddly enough our SDK does show in the sample). Use AAD for your authentication, and the Implicit Flow to accomplish this.
In terms of the AAD integration, keep in mind that the APIs expect the schema version to match one that supports the bearer authentication, and to set the date on your request. Aside from that, in case of issues, check the troubleshooting guide!
Yet again I hope that this post was as useful for you, as it was for me! 😉