This post provides a lightweight implementation of the OAuth implicit flow grant for obtaining an access token. Implicit flow is appropriate when the current user is authenticated to a common identity provider (e.g. Azure Active Directory a.k.a AAD) and the client (the environment requesting the token) is not secure. A great example of this is making a call to the Microsoft Graph from a page in SharePoint Online using only JavaScript.
The ADAL.js library exists as an authentication solution specifically for when working against AAD as the identity provider. Unfortunately, it is currently not well maintained and is over complicated. EDIT: ADAL.js has been updated multiple times since this post was first written and I would recommend using it. From a user experience perspective, the implementation discussed in this post avoids the need to redirect in order to authenticate. It happens seamlessly in the background via a hidden iframe.
Azure Active Directory
A great article on the OAuth grants, agnostic of implementation, can be found here.
Thanks to my colleague Paul Lawrence for writing the first iteration of this code.
This code has a dependency on jQuery, mostly just for promises. I know, old school. I expect I’ll write an es6/2016 version of this soon enough but it shouldn’t be a challenge to convert this code yourself.
As I know I’ll get comments about it if I don’t mention it, this code doesn’t send and verify a state token as part of the grant flow. This is optional as far as the OAuth specification is concerned but it should be done as an additional security measure.
Although I’m Microsoft stack developer and have only tested this with AAD as the identity provider, I believe that it should work for any identify provider that adheres to the OAuth specification for authentication. You would need to play around with the authorisation server URL as login.microsoftonline.com is specifically for authenticating to AAD. I’d love feedback on this.
By definition, the OAuth implicit flow grant does not return a refresh token. Furthermore, the access token has a short lifetime, an hour I believe, and credentials must be re-entered before additional access tokens can be obtained via the implicit flow grant. The code provided in this post handles this by returning a URL which can be used to re-authenticate when a request fails. This URL can be used behind a link or redirection could be forced to occur automatically.
The following code snippet is an example of using this implicit flow library to call into the Microsoft Graph from within the context of a SharePoint Online page.
You will need to provide an appropriate AAD app ID for your AAD app. And don’t forget that you need to enable implicit flow via the app manifest and associate the correct delegate permissions.
This code should work not only with the Microsoft Graph but also to SharePoint Online endpoints, other AAD secured resources such as Azure services or your own AAD secured and CORS enabled web API.
[See note above about identity providers other than AAD]
Here is the implicit flow library code itself.
And here is the definition of the cache functions used above. Nothing special here, this could be swapped out with any cache implementation or removed altogether if caching is truly unnecessary or a security concern.
I welcome your comments, especially from anyone who gives this a go outside of Office 365 and the Microsoft stack.
As a developer my professional interests are technical and tend to be SharePoint focused. I've been working with SharePoint since 2009 and hope my posts will give back a little to the community that's supported me over this time. I'm also a keen runner (half-marathon) and passionate Brompton bicycle owner.
View all posts by Paul Ryan
10 thoughts on “OAuth Implicit Flow in JS without ADAL.js”
Hi,
First of all let me congratulate you for this excellent work.
From my tests, it all works great, but a comment should be concerning the value referred in “redirectUrl”:
var redirectUrl = _spPageContextInfo.webAbsoluteUrl + “/_layouts/images/blank.gif”;
This works, but one also needs to register this very same URL in the AAD app as “Reply URL”, otherwise it will give an exception stating that at least one Reply URL must be configured. At least to me this aspect wasn’t clear. All of the rest seems to work just fine.
Hi Paul,
I receive the following error, when trying to use your solution. When I paste the authUri url in the browser I get back a token though.. I created a solution using adal.js in an iFrame last week, but this stopped working as well. This is how I got on your blog.. Can you please help me out? Maybe you know what I am doing wrong.
Refused to display ‘https://login.microsoftonline.com/common/oauth2/authorize?client_id=f8cae3e…2F_layouts%2Fimages%2Fblank.gif&resource=https%3A%2F%2Fgraph.microsoft.com’ in a frame because it set ‘X-Frame-Options’ to ‘deny’.
The error you are receiving will be the same for *any* authentication error because the error page which the iframe redirects to cannot be displayed in the iframe (The error is just stating that it can’t display a page from another domain).
Check that your redirect URLs are correct. You should list both the page from which the call is being made as well as the /_layouts/images/blank.gif which the iframe redirects to.
I would recommend using ADAL.js at this time.
Having said that, the first code sample provided demonstrates making a call to fetch a bearer token for authenticating to the Microsoft Graph. If you need more guidance than this please refer the documentation for the API endpoint you are attempting to authenticate to. Paul.
Hey Paul,
we are trying to build a custom Web API for Office 365 using Azure AD. The problem is the “redirect in order to authenticate” you mentioned in your post above. We do not want that the user loses the site context in order to use the webservices.
Your EDIT says that it adal.js has been improved but we can not find anything if there is now another possibility to avoid the redirect?
If this is not the case: Are there any other possibilities to authenticate the sharepoint users in a custom webservice?
Hi Quantum, The redirection can occur within an iFrame rather than the main page. This is what happens in the code I provide in this post and what happens with ADAL.js if it is configured correctly.
The important factors to achieving this are: 1) the iFramed redirect URL is on the same domain as the host page, 2) implicit flow is enabled, 3) the AAD login URL includes the tenant ID – the specific AAD instance endpoint must be referenced. Implicit flow cannot work against the ‘common’ endpoint and you’ll be promped for credentials if you try except that the iframe will refuse to display the prompt as it will cause a cross domain exception, 4) The AAD app registration must include permissions to access your Web API, 5) you pass the access token retrieved with your call to the Web API.
In summary, you absolutely can achieve what you want – a Web API secured with AAD which can be authenticated with silently from the context of Office 365.
Hey Paul,
thanks for the detailed answer. Do you know if there are any articles showing the steps how to achieve this?
Hi,
First of all let me congratulate you for this excellent work.
From my tests, it all works great, but a comment should be concerning the value referred in “redirectUrl”:
var redirectUrl = _spPageContextInfo.webAbsoluteUrl + “/_layouts/images/blank.gif”;
This works, but one also needs to register this very same URL in the AAD app as “Reply URL”, otherwise it will give an exception stating that at least one Reply URL must be configured. At least to me this aspect wasn’t clear. All of the rest seems to work just fine.
Thank you!
Nuno
Hi Paul,
I receive the following error, when trying to use your solution. When I paste the authUri url in the browser I get back a token though.. I created a solution using adal.js in an iFrame last week, but this stopped working as well. This is how I got on your blog.. Can you please help me out? Maybe you know what I am doing wrong.
Refused to display ‘https://login.microsoftonline.com/common/oauth2/authorize?client_id=f8cae3e…2F_layouts%2Fimages%2Fblank.gif&resource=https%3A%2F%2Fgraph.microsoft.com’ in a frame because it set ‘X-Frame-Options’ to ‘deny’.
The error you are receiving will be the same for *any* authentication error because the error page which the iframe redirects to cannot be displayed in the iframe (The error is just stating that it can’t display a page from another domain).
Check that your redirect URLs are correct. You should list both the page from which the call is being made as well as the /_layouts/images/blank.gif which the iframe redirects to.
How do you implement this ?
I would recommend using ADAL.js at this time.
Having said that, the first code sample provided demonstrates making a call to fetch a bearer token for authenticating to the Microsoft Graph. If you need more guidance than this please refer the documentation for the API endpoint you are attempting to authenticate to. Paul.
Hey Paul,
we are trying to build a custom Web API for Office 365 using Azure AD. The problem is the “redirect in order to authenticate” you mentioned in your post above. We do not want that the user loses the site context in order to use the webservices.
Your EDIT says that it adal.js has been improved but we can not find anything if there is now another possibility to avoid the redirect?
If this is not the case: Are there any other possibilities to authenticate the sharepoint users in a custom webservice?
Hi Quantum, The redirection can occur within an iFrame rather than the main page. This is what happens in the code I provide in this post and what happens with ADAL.js if it is configured correctly.
The important factors to achieving this are: 1) the iFramed redirect URL is on the same domain as the host page, 2) implicit flow is enabled, 3) the AAD login URL includes the tenant ID – the specific AAD instance endpoint must be referenced. Implicit flow cannot work against the ‘common’ endpoint and you’ll be promped for credentials if you try except that the iframe will refuse to display the prompt as it will cause a cross domain exception, 4) The AAD app registration must include permissions to access your Web API, 5) you pass the access token retrieved with your call to the Web API.
In summary, you absolutely can achieve what you want – a Web API secured with AAD which can be authenticated with silently from the context of Office 365.
Hey Paul,
thanks for the detailed answer. Do you know if there are any articles showing the steps how to achieve this?
We tried Rob Windors walktrough (https://blogs.msmvps.com/windsor/2017/03/12/walkthrough-building-a-custom-web-api-for-use-with-sharepoint-online/) but it does not deal with the redirect problem.
Hey Paul.
We tried a lot of adal examples but the adal library still has to many bugs and problems (redirect, problems in ie…).
Therefore we tried your code again and changed it a bit. Now it is working without problems.
Thank you for your code! It helped us a lot.
Great to hear it! Glad to have helped and thanks for the feedback.