Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I make Spring Security OAuth2 work with load balancer?

We currently have 4 Spring applications that use Spring Security Oauth2 project for authentication. The applications are REST APIs that are consumed by other internal applications in the company I work for.

Everything was working fine in the development and QA environments as we were not doing load balancing, now that we are in pre-production we are facing an issue with the load balancer (LB).

This is the workflow for this issue:

  1. Client sends request for the oauth token
  2. LB redirects the request to Box 1
  3. Box 1 authenticates and returns a valid Bearer Token
  4. Client receives the token and store it for using through the sesion
  5. Client sends request for a service in the REST API adding the previously retrieved token to the headers
  6. LB redirects the request to Box 2
  7. Box 2 fails to authenticate as it does not recognize the token and returns an Invalid Credentials response

We are using an in memory user store:

<bean id="tokenStore" class="org.springframework.security.oauth2.provider.token.InMemoryTokenStore" />

Is there a way to make different boxes to share the same token store? I know there is a JdbcTokenStore that can be used to persist tokens to the db, but I would prefer to avoid persisting tokens as these applications point to a legacy database that only stores business information.

like image 261
raspacorp Avatar asked Sep 16 '13 20:09

raspacorp


People also ask

What is OAuth 2.0 and how it works in spring boot?

OAuth2 is an authorization framework that enables the application Web Security to access the resources from the client. To build an OAuth2 application, we need to focus on the Grant Type (Authorization code), Client ID and Client secret.

How does OAuth2 work in REST API spring boot?

It works by delegating user authentication to the service that hosts the user account and authorizing third-party applications to access the user account. Oauth2 provides authorization flows for web and desktop applications, and mobile devices.

Does spring boot support OAuth2?

Spring Security and Spring Boot permit to quickly set up a complete OAuth2 authorization/authentication server in an almost declarative manner. The setup can be further shortened by configuring OAuth2 client's properties directly from application. properties/yml file, as explained in this tutorial.


1 Answers

I'm a bit late to this question, but maybe this will help someone searching for a similar answer. There are two major things you need to watch out for when using multiple oauth servers on a load balancer:

As @chris-h alluded to in his answer, you need to ensure that the information backing an access token issued by any of the oauth servers can be read (and trusted) by any of the other oauth servers. You can use a JDBC token store as he suggested, but this has the disadvantage that if Server A has to validate an access token issued by Server B, it always has to hit the database to do so.

A better solution (IMO) is to use JWT access tokens, where all the information needed to validate the token is encrypted within it. So long as all oauth servers use the same encryption key, they can read the data in each other's access tokens and trust that the data is valid since it is encrypted. The advantage is there are no database calls needed to validate an access token. The disadvantage is that there's no easy way to invalidate an access token once it's been issued. If you ever wondered why refresh tokens are needed when you could just increase the expire time of the access tokens themselves, this is the biggest reason.

The second thing to be aware of is that the Spring oauth implementation uses sessions to keep track of where the user is an the authentication process. If you aren't careful, you could wind up in an "endless loop" scenario. Suppose you have two oauth servers--Server A and Server B:

  1. The user goes to a web page or service which requires authentication, so gets redirected to "foo.com/oauth/authorize". The load balancer sends this request to Server A.
  2. Since Server A doesn't have any session information which proves the user is already authenticated, it redirects the user to the login page at foo.com/oauth/login. The redirect goes back through the load balancer, and since the load balancer is working in a "round-robin" fashion, this time it sends the request to Server B.
  3. The user logs in successfully, so session information is written to keep track of this. This session information is only known to Server B.
  4. Since the login was successful, the user gets redirected back to "foo.com/oauth/authorize" to continue the authentication process. Once again the redirect goes back through the load balancer. Since the load balancer is working in a "round-robin" fashion, this time it sends the request to Server A. But Server A doesn't know about the successful login that happened on Server B. Go back to step 2!

Probably the best (current) solution to this problem is to ensure that your load balancer supports "sticky sessions"--that is, once it sends a particular user to Server A or Server B, it always sends that user to the same server for a while.

A better solution might be for oauth implementations to not use sessions at all. Instead, use encrypted data passed as a parameter to /oauth/* that denotes where you are in the login process. Similar to how JWT tokens work, the information can be trusted by all servers if they all share the encryption key.

like image 191
Alvin Thompson Avatar answered Oct 09 '22 06:10

Alvin Thompson