[Solved] How to implement OAuth 2.0 Authorization Code Grant from Single-Page Application?



  • This is a cross-post from StackOverflow, I thought I'd ask here in case anyone had some insight into this problem.

    We have an Angular SPA backed by an ASP.NET Web API that uses the OAuth 2.0 Resource Owner Password Credentials Grant with a Bearer Token for authorisation. The API uses Microsoft.Owin.Security.OAuth to implement OAuth.

    We're trying to integrate with a third-party application that will use the Authorization Code Grant so users can authorise it to access our application on their behalf.

    We want the authorisation page to be a part of the SPA, but I'm having trouble figuring out how to submit the authorisation request from the SPA to the API and have it redirect back to the third-party application.

    I've tried using both AJAX (like all the other API requests in the SPA) and a regular HTML form (so that redirect responses redirect the page).

    We were originally sending back a JSON response from the API and letting the SPA do the redirection itself, but OWIN will automatically send a redirect response if there's some error; so there doesn't appear to be any way to avoid redirect responses.

    If I send the request via AJAX, the browser will automatically follow the redirect responses sent by the server by sending another AJAX request instead of redirecting the page.

    If I use a regular HTML form to send the request, there doesn't seem to be any way to send the required Authorization header with the Bearer Token.


  • Notification Spam Recipient

    Wait, so you're having the user enter theretheir creds inside your SPA, in order to OAuth them to another server? That doesn't sound right at all, and I'm going to stop lest my assumptions overcome me...



  • @Tsaukpaetra said in How to implement OAuth 2.0 Authorization Code Grant from Single-Page Application?:

    Wait, so you're having the user enter theretheir creds inside your SPA, in order to OAuth them to another server? That doesn't sound right at all, and I'm going to stop lest my assumptions overcome me...

    The goal is for users to grant the third-party application permission to read and write the data they see inside the SPA. This reading and writing is done through the same API that the SPA uses.

    The SPA and API are essentially two layers of the same application.

    When the user asks the third-party application to connect to our application, the following should happen:

    • The third-party application redirects the browser to our authorisation page in the SPA with the required query parameters
    • The user logs into the SPA as normal
    • The user grants permission for the third-party application to access their account
    • The API generates an authorisation code
    • The browser is redirected back to a specific page in the third-party application with the authorisation code as a query parameter
    • The third-party application server exchanges the authorisation code for an access token using our API
    • The third-party application server makes whatever API calls it needs to using the access token

    This is the same kind of flow used for logging into a site with GitHub or Facebook.


  • Notification Spam Recipient

    @Choonster Okay, so it's other apps that want to OAuth to yours. Gotcha.

    ...
    ...

    So, why doesn't javacript's window.location work for you again?

    Your API endpoint gets you the challenge token, you take that and splice it into the return URL, and set the location, and BAM, done.

    I don't see any reason why you need to redirect from the API server directly.



  • @Tsaukpaetra said in How to implement OAuth 2.0 Authorization Code Grant from Single-Page Application?:

    @Choonster Okay, so it's other apps that want to OAuth to yours. Gotcha.

    ...
    ...

    So, why doesn't javacript's window.location work for you again?

    Your API endpoint gets you the challenge token, you take that and splice it into the return URL, and set the location, and BAM, done.

    I don't see any reason why you need to redirect from the API server directly.

    The problem with this approach is that OWIN itself sends redirect responses in several scenarios (e.g. if some of the provided parameters are invalid) and there doesn't seem to be any way to prevent this.


  • Notification Spam Recipient

    @Choonster said in How to implement OAuth 2.0 Authorization Code Grant from Single-Page Application?:

    OWIN itself sends redirect responses in several scenarios

    🤔 I wonder if this is why I have the token endpoint wrapped internally on our website...

    Yes, the website talks to itself when you ask it for tokens, there's a good reason for that! :mlp_crazy:


  • Fake News

    @Choonster said in How to implement OAuth 2.0 Authorization Code Grant from Single-Page Application?:

    @Tsaukpaetra said in How to implement OAuth 2.0 Authorization Code Grant from Single-Page Application?:

    @Choonster Okay, so it's other apps that want to OAuth to yours. Gotcha.

    ...
    ...

    So, why doesn't javacript's window.location work for you again?

    Your API endpoint gets you the challenge token, you take that and splice it into the return URL, and set the location, and BAM, done.

    I don't see any reason why you need to redirect from the API server directly.

    The problem with this approach is that OWIN itself sends redirect responses in several scenarios (e.g. if some of the provided parameters are invalid) and there doesn't seem to be any way to prevent this.

    EDIT EDIT: I only figured out by now that likely you are already using everything in the article (which uses the other, simpler flow as you stated in your original post) and are looking for the more complex flow. Sorry for the confusion.


    The problem is that these middlewares are out of the box setup for ASP.NET MVC, where they can assume control because the frontend browser is sent to and fro using redirects, but once you start using it in AJAX calls that becomes rubbish.

    I did find this StackOverflow post which links to a bunch of blog articles of somebody using ASP.NET together with Angular. At one point in the first article they're using a OAuthAuthorizationServerOptions class which might actually change the behaviour of the middleware enough that no redirects are used.

    To be honest though, every time we used OpenId Connect in the past (which builds on OAuth 2) we rolled it by hand. It does take a couple of weeks to become well-versed in the spec and implement it.

    EDIT: BTW: What are you currently using to authenticate the SPA to the API?



  • @JBert said in How to implement OAuth 2.0 Authorization Code Grant from Single-Page Application?:

    @Choonster said in How to implement OAuth 2.0 Authorization Code Grant from Single-Page Application?:

    @Tsaukpaetra said in How to implement OAuth 2.0 Authorization Code Grant from Single-Page Application?:

    @Choonster Okay, so it's other apps that want to OAuth to yours. Gotcha.

    ...
    ...

    So, why doesn't javacript's window.location work for you again?

    Your API endpoint gets you the challenge token, you take that and splice it into the return URL, and set the location, and BAM, done.

    I don't see any reason why you need to redirect from the API server directly.

    The problem with this approach is that OWIN itself sends redirect responses in several scenarios (e.g. if some of the provided parameters are invalid) and there doesn't seem to be any way to prevent this.

    EDIT EDIT: I only figured out by now that likely you are already using everything in the article (which uses the other, simpler flow as you stated in your original post) and are looking for the more complex flow. Sorry for the confusion.

    Yes, those articles mainly cover what we're already doing (with the addition of external logins, which isn't what we're trying to achieve).



  • I ended up using a HTML form and sending the current access token in the form body. I created a hidden input in the form for the access token and only set its value when the form was being submitted (to reduce the chance of it being seen by the user or a malicious script/extension).

    On the server side, our OAuth code was previously only looking for the access token in the Authorization header; I changed it to also look in the request form (IOwinRequest.ReadFormAsync) for authorization code requests.

    The OAuth code now sends a redirect response to a successful authorization code request instead of sending a JSON response with the redirect URI.


Log in to reply