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 toAuthenticationMethod
s - Each
AuthenticationMethod
has exactly oneAuthenticationProvider
(e.g.google
,github
,local
) and stores thesub
of this authentication method and the correspondingUser
. In case of a local authentication, it is the User's ID. - Each
AuthenticationMethod
withAuthenticationProvider == 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?