0

I am currently developing a web service with Spring. I would like to provide users the possibility to login via external OAuth-Services, e.g. Google, Github,... as well as a traditional username/password-login. POJO-wise, I have the following setup:

  • Each User has a One-to-Many relation to AuthenticationMethods
  • Each AuthenticationMethod has exactly one AuthenticationProvider (e.g. google, github, local) and stores the sub of this authentication method and the corresponding User. In case of a local authentication, it is the User's ID.
  • Each AuthenticationMethod with AuthenticationProvider == local additionally stores a password.

What already works

Local authentication (username/password) is done through an own OAuth2 authentication server (part of the Spring application) and returns an JWTAccessToken , containing the username (the frontend never sees the client_secret, thus a password grant is acceptible in this situation).

I am also able to retrieve access tokens from the external OAuth Providers (Google, Github,...) via the authorization_request grant process containing their user'S sup from said provider.

Problem

I need to map the external sub to a User object. Since, in theory, two different users could have the same sub at two different, external providers, I would have to check the issuer as well, resulting in a nasty if-else construct. Also, this translation from JWT token to a User must be performed with every access where authorization is required.

Ideas for solutions

What I would like to do is add information to the externally generated JWT. This is obviously not possible since I cannot "re-sign" the external JWT. My idea is to intercept the external JWT and issue a local JWT, containing the username, thus using the external JWT only for initial authentication.

Is there a built-in possibility in Spring to accomplish what I want? Or is there a "best-practice" to solve this problem?

Spectric
  • 30,714
  • 6
  • 20
  • 43
Turing85
  • 18,217
  • 7
  • 33
  • 58

1 Answers1

0

The best practice is to have OAuth2 server to add username as an additional claim to JWT. Spring already has a handle that takes "user_name" claim from JWT and uses it as Principal object.

tsolakp
  • 5,858
  • 1
  • 22
  • 28
  • Problem is: I cannot change the external access tokens, therefore I cannot add additional claims. – Turing85 Oct 02 '17 at 21:52
  • I dont think Spring has anything built in to help in your case then. Have you checked the JWT token from the OAuth2 servers? Maybe they have additional claims you could use to get user name from. – tsolakp Oct 02 '17 at 21:57
  • The tokens are not the issue. I can find a `User` corresponding to a token. Problem is the token interception. I do not want that the frontend sees the external token. – Turing85 Oct 02 '17 at 21:59
  • @Turing85 Why not? The user getting the token from the external provider is authenticated as being the owner of the details in the token. You have to have the user pass you the data. I think you should be looking at having the email claim always attached to the token. Sorry I don't know how to implement this in Spring, but essentially you want to validate the token from the user (in ASP we using Owin middilewhere to automatically do this), then get the user Claims which should have their email. – Worthy7 May 28 '18 at 01:35
  • Any user can send data to your server. JWT contains raw readable data, and also a signed version of the same data. To make sure this is legit, your backend needs to use *Google's public key* to decode the *signature* of the JWT and check it is the same as the payload data. A user cannot send you a faked JWT because they cannot encode the data (google has to do it). Google makes it slightly more difficult because they include another step with the access code (for other reasons) but the concept remains : https://lostechies.com/content/jimmybogard/uploads/2014/11/image.png – Worthy7 May 28 '18 at 01:39