spring-projects / spring-security

Spring Security
http://spring.io/projects/spring-security
Apache License 2.0
8.8k stars 5.9k forks source link

Support For OAuth Login For Separate Api And UI Server #5938

Closed ankurpathak closed 6 years ago

ankurpathak commented 6 years ago

Currently OAuth Login Support Works Only When We Have API AND UI Application packaged as One Application. What if we havae separate API and UI Server? I mean we initiate login with Vendor on UI Server and point the Redirect URI to API Server. Something Similar to Flow mentioned in this Grails plugin: https://alvarosanchez.github.io/grails-spring-security-rest/2.0.0.RC1/docs/index.html#oauth

jgrandja commented 6 years ago

@ankurpathak

we initiate login with Vendor on UI Server and point the Redirect URI to API Server

The Authorization Request and subsequent Authorization Response must be processed by the same system. So the UI Server or the Grails system in the linked sequence diagram must process both - Authorization request/response.

You cannot have the UI Server trigger the Authorization Request and the API Server process the Authorization Response. How would the API server correlate the incoming Authorization Response with the previously saved Authorization Request that was triggered and saved in the UI Server?

Looking at the sequence diagram in the provided link, oauth2Login supports this flow. The only variation I'm noticing in that flow is Step 6

Browser navigates to that Grails callback URL. Then, Grails will use OAuth to fetch user information (like email) from Google. Based on that, will generate a REST API token and fetch and store principal information. The response from Grails will be a front-end URL where the token is a parameter.

Notice the last step (in bold), this can be achieved by configuring a custom AuthenticationSuccessHandler via http.oauth2Login().successHandler(customAuthenticationSuccessHandler). The AuthenticationSuccessHandler would need to be injected with OAuth2AuthorizedClientRepository and lookup the OAuth2AuthorizedClient using the provided OAuth2AuthenticationToken.getAuthorizedClientRegistrationId() which will provide you access to the OAuth2AuthorizedClient.accessToken.

However, I would not recommend performing a redirect back to the Browser/Javascript client with the access token as a parameter. It is very risky to expose a credential to an untrusted client like a browser. The access token can easily be leaked. You really should use the session identifier between the browser client and server (UI) application and delegate protected resource calls to the server (UI) app.

Does this answer your question?

ankurpathak commented 6 years ago

@jgrandja

  1. API Server(api.example.com): The Grails Server IN Sequence Diagram is infact ApiServer I guess(Corect me If I am wrong)
  2. UI Server(Angular or React)(example.com) : will be some arbitary server(Amazon S3 for website hosting, Github for website hosting) is just shown as browser in sequence diagram. Because whole UI will be loaded inbrowser in just one call to index.html
  3. We initiate the request to OAuth Provider form browser(example.com) in browser address bar and with redirect uri pointing to api.example.com/oauth/provider.
  4. After login with provider it will send a redirect to browser with location of Api server(api.example.com/oauth/provider) and AuthorizationCode in that location.
  5. Browser will send a redirect request to API server andbecause of this no AuthorizationCode will be visible in browser
  6. ApiServer will exchange AuthorizationCode for AccessToken.
  7. All this will happen on HTTPS and API server(Grails in Sequence Diagram) receives the AccessToken not browser.
  8. So I think this flow is safe to use and I don't see any security risk in it. Is this flow supported by OAuth login of Spring Security 5 and how??
ankurpathak commented 6 years ago
  1. So Api Server(api.example.com) and UI sever(example.com) are separate in this case.
  2. So this flow is compatible with Mobile applications even without using Web View in applications.
  3. The flow in Spring Security 5 for OAuth Login with API(example.com/api) and UI(example.com) on One Server is not useful for Mobile Application without using web view(api.example/api is same context as example.com i.e sub resource of example.com not separate application in same tomcat).
  4. Respnse from Api Server(Grails) will be Access Token To My Server not Access Token Of OAuth Provider. Hence It can be used with Mobile Applications without webview.
  5. Grails is mentioned in that sequence digram in Ours case it will be Spring Boot,
jgrandja commented 6 years ago

@ankurpathak

  1. API Server(api.example.com): The Grails Server IN Sequence Diagram is infact ApiServer I guess(Corect me If I am wrong)

Just so we're on the same page. The Grails Server in the sequence diagram is for the most part implemented by oauth2Login(). I say for the most part because there are a couple of steps in the sequence that are not handled. I find it a little confusing actually because it seems you are trying to combine the Implicit and Authorization Code flow into one? Or maybe I'm not interpreting that diagram properly.

Either way, oauth2Login is implemented using the Authorization Code grant. You can find a sample of it here. And plenty or reference docs as well.

  1. UI Server(Angular or React)(example.com) : will be some arbitary server(Amazon S3 for website hosting, Github for website hosting) is just shown as browser in sequence diagram. Because whole UI will be loaded inbrowser in just one call to index.html

Can you clarify if you're looking to implement the Implicit flow for your use case?

ankurpathak commented 6 years ago

@jgrandja No I am not looking for Implicit Grand Type. I am looking for Authrization Code Grand Type. Main point is we have to do oauth2Login() in case we have UI(Angular or React) and API (Spring Boot) hosted at two different domains(without making access token of oauth provider public). Can we implement it with current support? If not I am looking for that extra support in oauth2Login() because separate UI and API case is most common now a days.

jgrandja commented 6 years ago

@ankurpathak It looks to me that you need to make a change to your application architecture. Are you aware of the patterns API Gateway or the variation Backend for Front-End ?

Main point is we have to do oauth2Login() in case we have UI(Angular or React) and API (Spring Boot) hosted at two different domains(without making access token of oauth provider public)

For example, your UI Server would be your Gateway App (BFF) that would implement oauth2Login and could serve your Angular/React app. All communication from your Angular/React app would go through the Gateway App.

The Gateway App would delegate/call downstream services (API Server A, B, C, ...). The Access Token(s) would be stored on your Gateway App and pass it to downstream services.

FYI, we introduced Resource Server support in the recent 5.1 release so you can use these features to implement your API Server Apps. See the sample and reference doc.

ankurpathak commented 6 years ago

@jgrandja You cleared a lot on the issue and I read about Spring Netflix Zull and using it in my project. And Also I have merged both UI and API in one artifact by using mutti module project and still having the live time reload feature on angular module.

jgrandja commented 6 years ago

@ankurpathak I'm glad I was able to help. Another project you might want to look at is Spring Cloud Gateway.

ankurpathak commented 6 years ago

@jgrandja Thanks I will surely look at the Spring Cloud Gateway.