Announcement Announcement Module
Collapse
No announcement yet.
ClientTokenServices Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • ClientTokenServices

    Can someone explain what happened to OAuth2ClientTokenServices and its in memory implementation? They seem to have disappeared between M4 and M5, and I can't find any information about refactoring or recommended replacements. We'd like to be able to persist access and refresh tokens on the client side.

  • #2
    On the client side the tokens are stored in OAuth2ClientContext. Normally this is volatile but I suppose you could persist the tokens if you really needed to (you only really need the String values so it's trivial). Why not just obtain the token again from the server if you don't have one in memory? If the user is authenticated it shouldn't be a big deal.

    Comment


    • #3
      Originally posted by Dave Syer View Post
      On the client side the tokens are stored in OAuth2ClientContext. Normally this is volatile but I suppose you could persist the tokens if you really needed to (you only really need the String values so it's trivial). Why not just obtain the token again from the server if you don't have one in memory? If the user is authenticated it shouldn't be a big deal.
      If we don't persist the refresh token, then how do we prevent the user from having to go through the authorization flow every time they log in to the client system? That should be a one time operation, and I believe that was the exact purpose of OAuth2ClientTokenServices.

      Comment


      • #4
        The token is stored on the server. It won't prompt for approval if there is a valid token (that definitely changed since M4, so I imagine that's why there is no more client-side support in the framework for caching). The problem really is that the client can and should be able to store tokens in whatever way it chooses - and it might not even have access to a Spring Security authentication when it does it, so how would the framework store tokens in a generic way that can be used by everyone? Maybe you could use Spring's @Cacheable support to handle it for you? I'm open to suggestion if you have a clear use case and some ideas about how to implement them, but I haven't personally needed any client-side caching of tokens (other than what is provided already by virtue of having HttpSessions in most user apps).

        Comment


        • #5
          Originally posted by Dave Syer View Post
          The token is stored on the server. It won't prompt for approval if there is a valid token
          I must be missing something, so let me lay out the problematic scenario I am seeing:
          1. The user logs in to the client application, establishing a security context.
          2. The user attempts to access a protected resource from the provider application for the first time, prompting the authorization flow.
          3. Upon authorization, the user has an access/refresh token, which is stored in their security context. They use this to access protected resources from the provider.
          4. The user logs out of the client application. Their security context, along with their HTTP session, is destroyed.
          5. The user logs back in to the client application at a later time. They have a new security context and a new HTTP session, neither of which has an access token.
          6. The user attempts to access a protected resource from the provider application, again prompting the authorization flow.

          I want the user to go through the authorization process one and only one time, which means the access/refresh token must persist somewhere outside the HTTP session. As recently as M5, AccessTokenProviderChain used OAuth2ClientTokenServices to perform exactly this function. Why remove something that does exactly what we need?

          Comment


          • #6
            Your list is correct up to a point. At step 6 the flow is started by the client, but the server is able to return the access token with no approval process, so from the user's point of view it is like a single sign on - the browser might follow a redirect, but he won't notice in general and won't need to approve anything. Given that, isn't it OK to consolidate the storage and caching in the server?

            Comment


            • #7
              Originally posted by Dave Syer View Post
              Your list is correct up to a point. At step 6 the flow is started by the client, but the server is able to return the access token with no approval process, so from the user's point of view it is like a single sign on - the browser might follow a redirect, but he won't notice in general and won't need to approve anything. Given that, isn't it OK to consolidate the storage and caching in the server?
              That isn't the behavior I see with the sparkler/tonr sample application. Once I log out of Tonr and then log back in, I have to log in to Sparklr again in order to see the photos, even though I had previously approved access. And I see the same behavior with the client and provider we're working with. It's worth noting that we don't have control over the provider implementation, so if the scenario you're describing requires something to change with the provider, then we're out luck.

              Caching tokens on the client side always made sense to me, it was simple and straightforward and it solved a very important problem for us.

              Comment


              • #8
                I'm not sure we are using the same sample code (did you get the latest?). When I log out of tonr and go to "sparklr pics" I have to re-authenticate with tonr (as expected), but then I see my pics right away without the browser having to render anything from sparklr, and without any more forms to submit.

                As far as the provider goes, I suppose it could well be one that requires authentication more often than sparklr does, and then you would need to re-authenticate. It might also be one that doesn't cache its tokens (but I'm not sure why it wouldn't). All the major OAuth2 vendors in the social space that I have tried keep a browser session and remember token grants. You didn't say you were using a third party provider, but please try to remain calm.

                Maybe we could look at a more explicitly cache-oriented solution to your problem? Spring has some nice features for that now, so I would be interested in seeing something that used @Cacheable on an AccessTokenProvider. That seems like the right level of abstraction to me.

                Comment


                • #9
                  Originally posted by Dave Syer View Post
                  I'm not sure we are using the same sample code (did you get the latest?). When I log out of tonr and go to "sparklr pics" I have to re-authenticate with tonr (as expected), but then I see my pics right away without the browser having to render anything from sparklr, and without any more forms to submit.

                  As far as the provider goes, I suppose it could well be one that requires authentication more often than sparklr does, and then you would need to re-authenticate. It might also be one that doesn't cache its tokens (but I'm not sure why it wouldn't). All the major OAuth2 vendors in the social space that I have tried keep a browser session and remember token grants. You didn't say you were using a third party provider, but please try to remain calm.

                  Maybe we could look at a more explicitly cache-oriented solution to your problem? Spring has some nice features for that now, so I would be interested in seeing something that used @Cacheable on an AccessTokenProvider. That seems like the right level of abstraction to me.
                  Who's not calm? I didn't use a frowny face or anything!

                  I am using the latest build snapshot, downloaded yesterday afternoon. In any browser, I constantly have to re-authenticate to sparklr (through the sparklr login form) to see the photos if I log out and back in to tonr.

                  As for our provider, it's not third party, but it is legacy, so its implementation is basically frozen. It does persist tokens, but whatever magic that is supposed to happen post-authorization in M6 doesn't seem to work properly with it. The OAuth2ClientTokenServices implementation in M5 does work.

                  As for @Cacheable, I am not sure that's the right idea. We need the tokens to persist, even between client restarts, so it's a need for persistence, not caching. From what little I know of @Cachable, it's addressing a different need.

                  Perhaps a compromise is to keep OAuth2ClientTokenServices in AccessTokenProviderChain, but set it to null and not use it by default. That gives the option of easily including it for those of us that need it. Otherwise, I guess we'll stick with M5 for now, and roll our own AccessTokenProvider with persisted tokens if we need to upgrade. I have to imagine other people have this need, though, so it does seem like it's worth keeping in the library. Thanks for the help.

                  Comment


                  • #10
                    Just as a reference as this post appears the first for ClientTokenServices, they exist and can be used but it is not documented and even the Wiki points to a class that does not exist.
                    This is the config working for me:

                    Code:
                    	<oauth:rest-template resource="XXX" id="oauthRestTemplate"
                    		access-token-provider="accessTokenProvider" />
                    
                    	<bean
                    		class="org.springframework.security.oauth2.client.token.AccessTokenProviderChain"
                    		id="accessTokenProvider">
                    		<constructor-arg>
                    			<list>
                    				<bean					class="org.springframework.security.oauth2.client.token.grant.code.AuthorizationCodeAccessTokenProvider" />
                    			</list>
                    		</constructor-arg>
                    		<property name="clientTokenServices" ref="clientTokenServices" />
                    	</bean>
                    
                    	<bean class="com.prot_on.box.security.ProtOnOAuth2ClientTokenServices"
                    		id="clientTokenServices" />

                    The constructor-arg is not needed but I only use that type of token so removed the other ones during test and I justs keep that.

                    com.prot_on.box.security.ProtOnOAuth2ClientTokenSe rvices will be your custom class for persisting Tokens that must implement ClientTokenServices

                    On a side note OAuth tokens can be easily persisted as JSon using Jackson but the expired_in field while be persisted also and will not be updated on deserialization (obviously) so you must need to update expiration or expiresIn accordingly.

                    Comment


                    • #11
                      Yeah, ClientTokenServices was added back last year (JIRA ref SECOAUTH-290). The documentation is in a docs/ subdir of the main source code now, so if you want to improve it a pull request would be perfect.

                      Comment


                      • #12
                        Originally posted by Dave Syer View Post
                        Yeah, ClientTokenServices was added back last year (JIRA ref SECOAUTH-290). The documentation is in a docs/ subdir of the main source code now, so if you want to improve it a pull request would be perfect.
                        Indeed that what I did: https://github.com/SpringSource/spri...-oauth/pull/88
                        Not sure if perfect as english is not my main language but at least it is updated to the lastest versions.

                        Comment

                        Working...
                        X