Is it possible to generate multiple valid access tokens using the client_credentials or password grant type per request?
Generating a token using the above grant types only gives a new token when the current one expires per request.
I can use the password grant type to generate a refresh token and then generate multiple access tokens, but doing that will invalidate any previous access tokens.
Any idea how i could change to allow an access token to be generated per request to the /oauth/token endpoint and insure that any previous tokens are not invalidated?
Below is the XML configuration of my oauth server.
<!-- oauth2 config start-->
<sec:http pattern="/test/oauth/token" create-session="never"
authentication-manager-ref="authenticationManager" >
<sec:intercept-url pattern="/test/oauth/token" access="IS_AUTHENTICATED_FULLY" />
<sec:anonymous enabled="false" />
<sec:http-basic entry-point-ref="clientAuthenticationEntryPoint"/>
<sec:custom-filter ref="clientCredentialsTokenEndpointFilter" before="BASIC_AUTH_FILTER" />
<sec:access-denied-handler ref="oauthAccessDeniedHandler" />
</sec:http>
<bean id="clientCredentialsTokenEndpointFilter"
class="org.springframework.security.oauth2.provider.client.ClientCredentialsTokenEndpointFilter">
<property name="authenticationManager" ref="authenticationManager" />
</bean>
<sec:authentication-manager alias="authenticationManager">
<sec:authentication-provider user-service-ref="clientDetailsUserService" />
</sec:authentication-manager>
<bean id="clientDetailsUserService"
class="org.springframework.security.oauth2.provider.client.ClientDetailsUserDetailsService">
<constructor-arg ref="clientDetails" />
</bean>
<bean id="clientDetails" class="org.security.oauth2.ClientDetailsServiceImpl"></bean>
<bean id="clientAuthenticationEntryPoint"
class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint">
<property name="realmName" value="springsec/client" />
<property name="typeName" value="Basic" />
</bean>
<bean id="oauthAccessDeniedHandler"
class="org.springframework.security.oauth2.provider.error.OAuth2AccessDeniedHandler"/>
<oauth:authorization-server
client-details-service-ref="clientDetails" token-services-ref="tokenServices">
<oauth:authorization-code />
<oauth:implicit/>
<oauth:refresh-token/>
<oauth:client-credentials />
<oauth:password authentication-manager-ref="userAuthenticationManager"/>
</oauth:authorization-server>
<sec:authentication-manager id="userAuthenticationManager">
<sec:authentication-provider ref="customUserAuthenticationProvider">
</sec:authentication-provider>
</sec:authentication-manager>
<bean id="customUserAuthenticationProvider"
class="org.security.oauth2.CustomUserAuthenticationProvider">
</bean>
<bean id="tokenServices"
class="org.springframework.security.oauth2.provider.token.DefaultTokenServices">
<property name="tokenStore" ref="tokenStore" />
<property name="supportRefreshToken" value="true" />
<property name="accessTokenValiditySeconds" value="300"></property>
<property name="clientDetailsService" ref="clientDetails" />
</bean>
<bean id="tokenStore" class="org.springframework.security.oauth2.provider.token.store.JdbcTokenStore">
<constructor-arg ref="jdbcTemplate" />
</bean>
<bean id="jdbcTemplate"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/oauthdb"/>
<property name="username" value="root"/>
<property name="password" value="password"/>
</bean>
<bean id="oauthAuthenticationEntryPoint"
class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint">
</bean>
Updated on 21/11/2014
When I double check, I found that
InMemoryTokenStore
use aOAuth2Authentication
's hash string as key of serveralMap
. And when I use same username, client_id, scope.. and I got samekey
. So this may leading to some problem. So I think the old way are deprecated. The following is what I did to avoid the problem.Create another
AuthenticationKeyGenerator
that can calculate unique key, calledUniqueAuthenticationKeyGenerator
Finally, wire them up
Below way may leading to some problem, see updated answer!!!
You are using DefaultTokenServices. Try this code and make sure to re-define your `tokenServices` package com.thanh.backend.oauth2.core; import java.util.Date; import java.util.UUID; import org.springframework.security.core.AuthenticationException; import org.springframework.security.oauth2.common.DefaultExpiringOAuth2RefreshToken; import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken; import org.springframework.security.oauth2.common.ExpiringOAuth2RefreshToken; import org.springframework.security.oauth2.common.OAuth2AccessToken; import org.springframework.security.oauth2.common.OAuth2RefreshToken; import org.springframework.security.oauth2.provider.OAuth2Authentication; import org.springframework.security.oauth2.provider.token.DefaultTokenServices; import org.springframework.security.oauth2.provider.token.TokenEnhancer; import org.springframework.security.oauth2.provider.token.TokenStore; /** * @author thanh */ public class SimpleTokenService extends DefaultTokenServices { private TokenStore tokenStore; private TokenEnhancer accessTokenEnhancer; @Override public OAuth2AccessToken createAccessToken(OAuth2Authentication authentication) throws AuthenticationException { OAuth2RefreshToken refreshToken = createRefreshToken(authentication);; OAuth2AccessToken accessToken = createAccessToken(authentication, refreshToken); tokenStore.storeAccessToken(accessToken, authentication); tokenStore.storeRefreshToken(refreshToken, authentication); return accessToken; } private OAuth2AccessToken createAccessToken(OAuth2Authentication authentication, OAuth2RefreshToken refreshToken) { DefaultOAuth2AccessToken token = new DefaultOAuth2AccessToken(UUID.randomUUID().toString()); int validitySeconds = getAccessTokenValiditySeconds(authentication.getOAuth2Request()); if (validitySeconds > 0) { token.setExpiration(new Date(System.currentTimeMillis() + (validitySeconds * 1000L))); } token.setRefreshToken(refreshToken); token.setScope(authentication.getOAuth2Request().getScope()); return accessTokenEnhancer != null ? accessTokenEnhancer.enhance(token, authentication) : token; } private ExpiringOAuth2RefreshToken createRefreshToken(OAuth2Authentication authentication) { if (!isSupportRefreshToken(authentication.getOAuth2Request())) { return null; } int validitySeconds = getRefreshTokenValiditySeconds(authentication.getOAuth2Request()); ExpiringOAuth2RefreshToken refreshToken = new DefaultExpiringOAuth2RefreshToken(UUID.randomUUID().toString(), new Date(System.currentTimeMillis() + (validitySeconds * 1000L))); return refreshToken; } @Override public void setTokenEnhancer(TokenEnhancer accessTokenEnhancer) { super.setTokenEnhancer(accessTokenEnhancer); this.accessTokenEnhancer = accessTokenEnhancer; } @Override public void setTokenStore(TokenStore tokenStore) { super.setTokenStore(tokenStore); this.tokenStore = tokenStore; } }