Spring security oauth2 - getting custom data from OAuth2 principal

16,480

Solution 1

You can override the Token creation class so the token himself would contain the username. (maybe encrypted using the client_secret). This way you can get the user related to a token from the token itself without additional data base access. you should override

<bean id="tokenServices" class="org.springframework.security.oauth2.provider.token.DefaultTokenServices">

with your own class, or use TokenEnhancer

Solution 2

Why you are not using Scopes which can be defined in client details and then use ScopeVoter to validate is this token have proper scope to access this resource or not.

please check my demo for more details

https://github.com/bassemZohdy/Spring_REST_OAuth_Demo

Update 1: I did not reply to part 2 of your question "getting custom data from OAuth2 principal" you can add rest service on your Authorization server which is be accessed using OAuth token to give you required information about this token user, so you do not have to care about "OAuth2 principal" you are dealing with Authorization server as resource server too.

Solution 3

In my opinion the right approach here would be to use the oauth2 "password" flow instead of client-credentials. you can create a general client-id and client-secret and give them to all of your users. each user can than request his own token using those client details and his own username and password. This way, each token would be connected to a UserDetails object which will solve your problem. You can see how this done here : https://labs.hybris.com/2012/06/18/trying-out-oauth2-via-curl/

Share:
16,480
Mark Doyle
Author by

Mark Doyle

Updated on June 18, 2022

Comments

  • Mark Doyle
    Mark Doyle almost 2 years

    I have a site that uses Spring security and has users (username & password) and standard form authentication. I allow users to generate a client Id and client secret linked to their account for use with an OAuth2 secured rest API.

    I use a separate client id & client secret for the API and not username and password so the user can change their password etc without breaking the API credentials, set specific scopes, disable API access etc.

    I use spring-security-oauth2 (provider) to secure the rest API and I have allowed a client credentials flow. I have setup client authentication for the api so that client id and secret are checked.

    From a separate application I use the client id and client secret to retreive an access token and start to use it with the api. For the most part I use simple @PreAuthorize expressions typically based on client roles and scope and these appear to work correctly.

    All above appears to work fine

    However... I have a few API endpoints now however where I need to implement some more complex rules based on some details from the underlying user - in this case the user that generated the client id and secret.

    As a simple example consider a messaging application where I have an endpoint that allows users to post a new "message" of a specific type that can vary. I have a table of allowed recipients for each user and each type and I want to check that the recipients of the posted message match the allowed recipient for the type. (User allowed recipients data is typically not large, and rarely changes so I'm happy to store a copy of it when generating an access token)

    I get the principal at these endpoints and I see it is an instance of OAuth2Authentication containing:

    • userAuthentication - null - This seems expectable for client credentials flow.
    • clientAuthentication is populated and authorizationParameters contains the grant type and client_id

    I suppose I could use the client id from clientAuthentication.authorizationParameters to lookup the user and the details I require, but that would be a few queries each api call which doesn't seem to make sense.

    I would guess there's a nice place/way in Spring OAuth2 libs that while granting the access token that I could add some extra details so that later I could get them from the OAuth2Authentication (principal) object (or something that extends it?)

    Alternatively is there a better approach entirely to such issue?

    Thx!

  • Mark Doyle
    Mark Doyle almost 11 years
    Thx for idea, but the point of using client credentials was to make the API generally independent of the users. Only in a few cases (minority) do I have some more complex rules. I've updated the question to give reasoning for the client credentials.
  • Mark Doyle
    Mark Doyle almost 11 years
    Thx, I'm using some simple scopes already but avoided that solution as I was worried about an exploding quantity of scopes to achieve the rules I wanted. I'll update the question with an example.
  • Bassem Reda Zohdy
    Bassem Reda Zohdy almost 11 years
    In another solution I'm using scope per group of resources I think there is no limitation on the nuber of scopes, also you can mix scopes with roles.
  • Mark Doyle
    Mark Doyle almost 11 years
    Thx, yeah I use such a bit already. Just for the case I mention it would be likely quite mind-bending to formulate the scopes from the user and then process them to interpret them :-) I'd hoped there was a better way.
  • Mark Doyle
    Mark Doyle almost 11 years
    Thx, initially sounds promising. I'll check it more and make some tests in the next day. I didn't find an article/post/sample yet so if you're aware of one please let me know :)
  • Mark Doyle
    Mark Doyle almost 11 years
    Hi, I checked and it seems the TokenEnhancer is useful to "enhance" the access token response and/or add some extra info. Although that's not what I want. There should be no need to send extra data back to to the client. While I understand your idea to try to stuff the username into the token (I often don't need it) it seems to me that there must be a better way that leaves tokens etc unchanged and just occurs on server side.
  • achiash
    achiash almost 11 years
    you can add the information you need to your Client Details when you register each client using ClientDetails.addAdditionalInformation Than you can retrive this information using the clientId you got. (this might require one query per request which seems to be reasonable)
  • Mark Doyle
    Mark Doyle almost 11 years
    Good point. Yeah the retrieval is a pity and what I wanted to avoid. Looks like the extension points/fields are just not there yet. I have my own impl. of TokenStore, ClientDetail, ClientDetailService, but seems I have to modify too much more to create a complete chain.
  • Makoto
    Makoto almost 9 years
    The link here is broken. Could you bring over a relevant snippet of this particular answer?
  • nurgasemetey
    nurgasemetey over 7 years
    Link is broken again.