diff --git a/openid-connect-server-webapp/src/main/webapp/resources/js/locale/en/messages.json b/openid-connect-server-webapp/src/main/webapp/resources/js/locale/en/messages.json
index e0b176d49..695ea44db 100644
--- a/openid-connect-server-webapp/src/main/webapp/resources/js/locale/en/messages.json
+++ b/openid-connect-server-webapp/src/main/webapp/resources/js/locale/en/messages.json
@@ -105,6 +105,7 @@
"refresh": "refresh",
"refresh-tokens": "Refresh Tokens",
"refresh-tokens-issued": "Refresh tokens are issued for this client",
+ "refresh-tokens-issued-help": "This will add the offline_access scope to the client's scopes.",
"refresh-tokens-reused": "Refresh tokens for this client are re-used",
"refresh-tokens-no-expire": "Refresh tokens do not time out",
"registered": "Registered at",
diff --git a/openid-connect-server-webapp/src/main/webapp/resources/template/client.html b/openid-connect-server-webapp/src/main/webapp/resources/template/client.html
index 9bdf4cba6..bc4acc2be 100644
--- a/openid-connect-server-webapp/src/main/webapp/resources/template/client.html
+++ b/openid-connect-server-webapp/src/main/webapp/resources/template/client.html
@@ -543,6 +543,7 @@
>
+
This will add the offline_access scope to the client's scopes.
diff --git a/openid-connect-server/src/main/java/org/mitre/oauth2/service/impl/DefaultOAuth2ProviderTokenService.java b/openid-connect-server/src/main/java/org/mitre/oauth2/service/impl/DefaultOAuth2ProviderTokenService.java
index 876475c74..ab95cbcd5 100644
--- a/openid-connect-server/src/main/java/org/mitre/oauth2/service/impl/DefaultOAuth2ProviderTokenService.java
+++ b/openid-connect-server/src/main/java/org/mitre/oauth2/service/impl/DefaultOAuth2ProviderTokenService.java
@@ -170,33 +170,7 @@ public class DefaultOAuth2ProviderTokenService implements OAuth2TokenEntityServi
// attach a refresh token, if this client is allowed to request them and the user gets the offline scope
if (client.isAllowRefresh() && token.getScope().contains(SystemScopeService.OFFLINE_ACCESS)) {
- OAuth2RefreshTokenEntity refreshToken = new OAuth2RefreshTokenEntity(); //refreshTokenFactory.createNewRefreshToken();
- JWTClaimsSet refreshClaims = new JWTClaimsSet();
-
-
- // make it expire if necessary
- if (client.getRefreshTokenValiditySeconds() != null) {
- Date expiration = new Date(System.currentTimeMillis() + (client.getRefreshTokenValiditySeconds() * 1000L));
- refreshToken.setExpiration(expiration);
- refreshClaims.setExpirationTime(expiration);
- }
-
- // set a random identifier
- refreshClaims.setJWTID(UUID.randomUUID().toString());
-
- // TODO: add issuer fields, signature to JWT
-
- PlainJWT refreshJwt = new PlainJWT(refreshClaims);
- refreshToken.setJwt(refreshJwt);
-
- //Add the authentication
- refreshToken.setAuthenticationHolder(authHolder);
- refreshToken.setClient(client);
-
-
-
- // save the token first so that we can set it to a member of the access token (NOTE: is this step necessary?)
- OAuth2RefreshTokenEntity savedRefreshToken = tokenRepository.saveRefreshToken(refreshToken);
+ OAuth2RefreshTokenEntity savedRefreshToken = createRefreshToken(client, authHolder);
token.setRefreshToken(savedRefreshToken);
}
@@ -229,6 +203,38 @@ public class DefaultOAuth2ProviderTokenService implements OAuth2TokenEntityServi
throw new AuthenticationCredentialsNotFoundException("No authentication credentials found");
}
+
+ private OAuth2RefreshTokenEntity createRefreshToken(ClientDetailsEntity client, AuthenticationHolderEntity authHolder) {
+ OAuth2RefreshTokenEntity refreshToken = new OAuth2RefreshTokenEntity(); //refreshTokenFactory.createNewRefreshToken();
+ JWTClaimsSet refreshClaims = new JWTClaimsSet();
+
+
+ // make it expire if necessary
+ if (client.getRefreshTokenValiditySeconds() != null) {
+ Date expiration = new Date(System.currentTimeMillis() + (client.getRefreshTokenValiditySeconds() * 1000L));
+ refreshToken.setExpiration(expiration);
+ refreshClaims.setExpirationTime(expiration);
+ }
+
+ // set a random identifier
+ refreshClaims.setJWTID(UUID.randomUUID().toString());
+
+ // TODO: add issuer fields, signature to JWT
+
+ PlainJWT refreshJwt = new PlainJWT(refreshClaims);
+ refreshToken.setJwt(refreshJwt);
+
+ //Add the authentication
+ refreshToken.setAuthenticationHolder(authHolder);
+ refreshToken.setClient(client);
+
+
+
+ // save the token first so that we can set it to a member of the access token (NOTE: is this step necessary?)
+ OAuth2RefreshTokenEntity savedRefreshToken = tokenRepository.saveRefreshToken(refreshToken);
+ return savedRefreshToken;
+ }
+
@Override
public OAuth2AccessTokenEntity refreshAccessToken(String refreshTokenValue, TokenRequest authRequest) throws AuthenticationException {
@@ -263,9 +269,6 @@ public class DefaultOAuth2ProviderTokenService implements OAuth2TokenEntityServi
throw new InvalidTokenException("Expired refresh token: " + refreshTokenValue);
}
- // TODO: have the option to recycle the refresh token here, too
- // for now, we just reuse it as long as it's valid, which is the original intent
-
OAuth2AccessTokenEntity token = new OAuth2AccessTokenEntity();
// get the stored scopes from the authentication holder's authorization request; these are the scopes associated with the refresh token
@@ -302,7 +305,17 @@ public class DefaultOAuth2ProviderTokenService implements OAuth2TokenEntityServi
token.setExpiration(expiration);
}
- token.setRefreshToken(refreshToken);
+ if (client.isReuseRefreshToken()) {
+ // if the client re-uses refresh tokens, do that
+ token.setRefreshToken(refreshToken);
+ } else {
+ // otherwise, make a new refresh token
+ OAuth2RefreshTokenEntity newRefresh = createRefreshToken(client, authHolder);
+ token.setRefreshToken(newRefresh);
+
+ // clean up the old refresh token
+ tokenRepository.removeRefreshToken(refreshToken);
+ }
token.setAuthenticationHolder(authHolder);