Organizational Research By

Surprising Reserch Topic

spring oauth2 generate access token per request to the token endpoint

spring oauth2 generate access token per request to the token endpoint  using -'java,spring,oauth,spring-security'

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" />

    <bean id="clientCredentialsTokenEndpointFilter"
        <property name="authenticationManager" ref="authenticationManager" />

    <sec:authentication-manager alias="authenticationManager">
        <sec:authentication-provider user-service-ref="clientDetailsUserService" />

    <bean id="clientDetailsUserService"
        <constructor-arg ref="clientDetails" />

    <bean id="clientDetails" class=""></bean>

    <bean id="clientAuthenticationEntryPoint"
        <property name="realmName" value="springsec/client" />
        <property name="typeName" value="Basic" />

    <bean id="oauthAccessDeniedHandler"

        client-details-service-ref="clientDetails" token-services-ref="tokenServices">
        <oauth:authorization-code />
        <oauth:client-credentials />
        <oauth:password authentication-manager-ref="userAuthenticationManager"/>

    <sec:authentication-manager id="userAuthenticationManager">
        <sec:authentication-provider  ref="customUserAuthenticationProvider">

    <bean id="customUserAuthenticationProvider"

    <bean id="tokenServices"
        <property name="tokenStore" ref="tokenStore" />
        <property name="supportRefreshToken" value="true" />
        <property name="accessTokenValiditySeconds" value="300"></property>
        <property name="clientDetailsService" ref="clientDetails" />

    <bean id="tokenStore" class="">
        <constructor-arg ref="jdbcTemplate" />

    <bean id="jdbcTemplate"
        <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 id="oauthAuthenticationEntryPoint"


asked Oct 6, 2015 by abhimca2006
0 votes

Related Hot Questions

1 Answer

0 votes

Updated on 21/11/2014

When I double check, I found that InMemoryTokenStore use a OAuth2Authentication's hash string as key of serveral Map. And when I use same username, client_id, scope.. and I got same key. 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, called UniqueAuthenticationKeyGenerator

 * Copyright 2006-2011 the original author or authors.
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
 * the License. You may obtain a copy of the License at
 * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
 * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations under the License.

 * Basic key generator taking into account the client id, scope, resource ids and username (principal name) if they
 * exist.
 * @author Dave Syer
 * @author thanh
public class UniqueAuthenticationKeyGenerator implements AuthenticationKeyGenerator {

    private static final String CLIENT_ID = "client_id";

    private static final String SCOPE = "scope";

    private static final String USERNAME = "username";

    private static final String UUID_KEY = "uuid";

    public String extractKey(OAuth2Authentication authentication) {
        Map values = new LinkedHashMap();
        OAuth2Request authorizationRequest = authentication.getOAuth2Request();
        if (!authentication.isClientOnly()) {
            values.put(USERNAME, authentication.getName());
        values.put(CLIENT_ID, authorizationRequest.getClientId());
        if (authorizationRequest.getScope() != null) {
            values.put(SCOPE, OAuth2Utils.formatParameterList(authorizationRequest.getScope()));
        Map extentions = authorizationRequest.getExtensions();
        String uuid = null;
        if (extentions == null) {
            extentions = new HashMap(1);
            uuid = UUID.randomUUID().toString();
            extentions.put(UUID_KEY, uuid);
        } else {
            uuid = (String) extentions.get(UUID_KEY);
            if (uuid == null) {
                uuid = UUID.randomUUID().toString();
                extentions.put(UUID_KEY, uuid);
        values.put(UUID_KEY, uuid);

        MessageDigest digest;
        try {
            digest = MessageDigest.getInstance("MD5");
        catch (NoSuchAlgorithmException e) {
            throw new IllegalStateException("MD5 algorithm not available.  Fatal (should be in the JDK).");

        try {
            byte[] bytes = digest.digest(values.toString().getBytes("UTF-8"));
            return String.format("%032x", new BigInteger(1, bytes));
        catch (UnsupportedEncodingException e) {
            throw new IllegalStateException("UTF-8 encoding not available.  Fatal (should be in the JDK).");

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; import; import; import; import; import; import; import; import; import; /** * @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; } }
answered Oct 6, 2015 by mannumits1