spring-security-oauth2-authorization-server client_secret_basic 认证模式
1.添加 RegisteredClient
class CLIENT_SECRET_BASIC extends AbstractClientTypeAuthorizationServerTests {
/**
* 添加测试注册客户端
*/
private void addRegisteredClient() {
RegisteredClient registeredClient = RegisteredClient.withId(new SnowFlake(31).nextId() + "")
.clientId(CLIENT_ID)
.clientSecret("{noop}" + CLIENT_SECRET)
.clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC)
.authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS)
.scope(OidcScopes.OPENID)
.scope(OidcScopes.PROFILE)
.build();
registeredClientRepository
.save(registeredClient);
}
}
2.发送请求
1. idea httprequest脚本
### client_secret_basic 请求方式
# state参数可选
# Authorization: Basic Base64(client_id:client_secret)
POST http://{{host}}:{{port}}/oauth2/token?grant_type=client_credentials&client_id={{client_id}}&state={{state}}
Content-Type: application/x-www-form-urlencoded
Authorization: Basic {{client_id}} {{client_secret}}
### 测试例子
POST http://localhost:5001/oauth2/token
Authorization: Basic test_client_secret_basic secret
Content-Type: application/x-www-form-urlencoded
grant_type=client_credentials&client_id=test_client_secret_basic
2.curl请求方式
curl -i -v -X POST -u "test_client_secret_basic:secret" -d "grant_type=client_credentials&client_id=test_client_secret_basic" http://localhost:5001/oauth2/token
3. apiPost文档
https://console-docs.apipost.cn/preview/5c835f3c5869ecba/f51728e8bf6cc72a?target_id=8657169f-7a42-4b29-935f-5f99ee0c8153
4.测试案例
https://gitee.com/elsfs/elsfs/blob/master/auth/spring-auth/src/test/java/org/elsfs/auth/client/CLIENT_SECRET_BASIC.java
.认证过程
1.进入OAuth2ClientAuthenticationFilter过滤器
public final class OAuth2ClientAuthenticationFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
/**
* 判断请求方式是不是 /oauth2/token', POST; /oauth2/introspect', POST;/oauth2/revoke, POST; /oauth2/device_authorization, POST
* 如果不是直接略过
*/
if (!this.requestMatcher.matches(request)) {
filterChain.doFilter(request, response);
return;
}
try {
/**
* (1)
* 到 DelegatingAuthenticationConverter筛选转换器
* 转化器 一共有4个 对应4种请求方式
* JwtClientAssertionAuthenticationConverter
* ClientSecretBasicAuthenticationConverter
* ClientSecretPostAuthenticationConverter
* PublicClientAuthenticationConverter
* 这里使用的是 ClientSecretBasicAuthenticationConverter 转换得到OAuth2ClientAuthenticationToken
*/
Authentication authenticationRequest = this.authenticationConverter.convert(request);
if (authenticationRequest instanceof AbstractAuthenticationToken) {
((AbstractAuthenticationToken) authenticationRequest).setDetails(
this.authenticationDetailsSource.buildDetails(request));
}
if (authenticationRequest != null) {
// 验证的客户端id是否符合oauth2规范
validateClientIdentifier(authenticationRequest);
/**
* (2)
* 在 ProviderManager 筛选 AuthenticationProvider 然后调用筛选的AuthenticationProvider authenticate方法返回Authentication对象
* 该处筛选 的是 ClientSecretAuthenticationProvider
*/
Authentication authenticationResult = this.authenticationManager.authenticate(authenticationRequest);
// 发布成功事件
this.authenticationSuccessHandler.onAuthenticationSuccess(request, response, authenticationResult);
}
filterChain.doFilter(request, response);
} catch (OAuth2AuthenticationException ex) {
if (this.logger.isTraceEnabled()) {
this.logger.trace(LogMessage.format("Client authentication failed: %s", ex.getError()), ex);
}
this.authenticationFailureHandler.onAuthenticationFailure(request, response, ex);
}
}
}
(2)
public final class ClientSecretBasicAuthenticationConverter implements AuthenticationConverter {
@Nullable
@Override
public Authentication convert(HttpServletRequest request) {
// 获取 Authorization
String header = request.getHeader(HttpHeaders.AUTHORIZATION);
if (header == null) {
return null;
}
// b把Basic 和token分离出来
String[] parts = header.split("\\s");
if (!parts[0].equalsIgnoreCase("Basic")) {
return null;
}
if (parts.length != 2) {
throw new OAuth2AuthenticationException(OAuth2ErrorCodes.INVALID_REQUEST);
}
byte[] decodedCredentials;
try {
decodedCredentials = Base64.getDecoder().decode(
parts[1].getBytes(StandardCharsets.UTF_8));
} catch (IllegalArgumentException ex) {
throw new OAuth2AuthenticationException(new OAuth2Error(OAuth2ErrorCodes.INVALID_REQUEST), ex);
}
String credentialsString = new String(decodedCredentials, StandardCharsets.UTF_8);
String[] credentials = credentialsString.split(":", 2);
if (credentials.length != 2 ||
!StringUtils.hasText(credentials[0]) ||
!StringUtils.hasText(credentials[1])) {
throw new OAuth2AuthenticationException(OAuth2ErrorCodes.INVALID_REQUEST);
}
// 获取 clientID和clientSecret
String clientID;
String clientSecret;
try {
clientID = URLDecoder.decode(credentials[0], StandardCharsets.UTF_8.name());
clientSecret = URLDecoder.decode(credentials[1], StandardCharsets.UTF_8.name());
} catch (Exception ex) {
throw new OAuth2AuthenticationException(new OAuth2Error(OAuth2ErrorCodes.INVALID_REQUEST), ex);
}
return new OAuth2ClientAuthenticationToken(clientID, ClientAuthenticationMethod.CLIENT_SECRET_BASIC, clientSecret,
OAuth2EndpointUtils.getParametersIfMatchesAuthorizationCodeGrantRequest(request));
}
}
(2)
public final class ClientSecretAuthenticationProvider implements AuthenticationProvider {
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
OAuth2ClientAuthenticationToken clientAuthentication =
(OAuth2ClientAuthenticationToken) authentication;
// 该 AuthenticationProvider 支持 client_secret_basic 和 client_secret_post
// 他们的区别就是请求参数是 body (client_secret_post)和 query(client_secret_basic)
if (!ClientAuthenticationMethod.CLIENT_SECRET_BASIC.equals(clientAuthentication.getClientAuthenticationMethod()) &&
!ClientAuthenticationMethod.CLIENT_SECRET_POST.equals(clientAuthentication.getClientAuthenticationMethod())) {
return null;
}
String clientId = clientAuthentication.getPrincipal().toString();
// 查询 RegisteredClient
RegisteredClient registeredClient = this.registeredClientRepository.findByClientId(clientId);
if (registeredClient == null) {
throwInvalidClient(OAuth2ParameterNames.CLIENT_ID);
}
if (this.logger.isTraceEnabled()) {
this.logger.trace("Retrieved registered client");
}
// 判断RegisteredClient是否支持该请求方式
if (!registeredClient.getClientAuthenticationMethods().contains(
clientAuthentication.getClientAuthenticationMethod())) {
throwInvalidClient("authentication_method");
}
if (clientAuthentication.getCredentials() == null) {
throwInvalidClient("credentials");
}
// 验证客户端密码
String clientSecret = clientAuthentication.getCredentials().toString();
if (!this.passwordEncoder.matches(clientSecret, registeredClient.getClientSecret())) {
throwInvalidClient(OAuth2ParameterNames.CLIENT_SECRET);
}
// 判断密码是否过期
if (registeredClient.getClientSecretExpiresAt() != null &&
Instant.now().isAfter(registeredClient.getClientSecretExpiresAt())) {
throwInvalidClient("client_secret_expires_at");
}
// 更新为安全密码
if (this.passwordEncoder.upgradeEncoding(registeredClient.getClientSecret())) {
registeredClient = RegisteredClient.from(registeredClient)
.clientSecret(this.passwordEncoder.encode(clientSecret))
.build();
this.registeredClientRepository.save(registeredClient);
}
if (this.logger.isTraceEnabled()) {
this.logger.trace("Validated client authentication parameters");
}
// 验证 code_verifier
// Validate the "code_verifier" parameter for the confidential client, if available
this.codeVerifierAuthenticator.authenticateIfAvailable(clientAuthentication, registeredClient);
if (this.logger.isTraceEnabled()) {
this.logger.trace("Authenticated client secret");
}
return new OAuth2ClientAuthenticationToken(registeredClient,
clientAuthentication.getClientAuthenticationMethod(), clientAuthentication.getCredentials());
}
}
生成token
public final class OAuth2TokenEndpointFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
// 判断是否 Post /oauth2/token
if (!this.tokenEndpointMatcher.matches(request)) {
filterChain.doFilter(request, response);
return;
}
try {
// client_credentials
String[] grantTypes = request.getParameterValues(OAuth2ParameterNames.GRANT_TYPE);
if (grantTypes == null || grantTypes.length != 1) {
throwError(OAuth2ErrorCodes.INVALID_REQUEST, OAuth2ParameterNames.GRANT_TYPE);
}
/**
*(1)
* 通过 DelegatingAuthenticationConverter 获取 OAuth2ClientCredentialsAuthenticationConverter 然后获取Authentication
* 这里的转化器一共有4个
* OAuth2AuthorizationCodeAuthenticationConverter
* OAuth2RefreshTokenAuthenticationConverter
* OAuth2ClientCredentialsAuthenticationConverter
* OAuth2DeviceCodeAuthenticationConverter
*/
Authentication authorizationGrantAuthentication = this.authenticationConverter.convert(request);
if (authorizationGrantAuthentication == null) {
throwError(OAuth2ErrorCodes.UNSUPPORTED_GRANT_TYPE, OAuth2ParameterNames.GRANT_TYPE);
}
if (authorizationGrantAuthentication instanceof AbstractAuthenticationToken) {
((AbstractAuthenticationToken) authorizationGrantAuthentication)
.setDetails(this.authenticationDetailsSource.buildDetails(request));
}
/**
* (2)
* 通过 ProviderManager 获取 OAuth2ClientCredentialsAuthenticationProvider 然后通过
* 该AuthenticationProvider获取OAuth2AccessTokenAuthenticationToken 至此完成认证返回token
*
*/
OAuth2AccessTokenAuthenticationToken accessTokenAuthentication =
(OAuth2AccessTokenAuthenticationToken) this.authenticationManager.authenticate(authorizationGrantAuthentication);
this.authenticationSuccessHandler.onAuthenticationSuccess(request, response, accessTokenAuthentication);
} catch (OAuth2AuthenticationException ex) {
SecurityContextHolder.clearContext();
if (this.logger.isTraceEnabled()) {
this.logger.trace(LogMessage.format("Token request failed: %s", ex.getError()), ex);
}
this.authenticationFailureHandler.onAuthenticationFailure(request, response, ex);
}
}
}
(2)
public final class OAuth2ClientCredentialsAuthenticationConverter implements AuthenticationConverter {
@Nullable
@Override
public Authentication convert(HttpServletRequest request) {
// grant_type = client_credentials 处理
String grantType = request.getParameter(OAuth2ParameterNames.GRANT_TYPE);
if (!AuthorizationGrantType.CLIENT_CREDENTIALS.getValue().equals(grantType)) {
return null;
}
// 获取 OAuth2ClientAuthenticationToken
Authentication clientPrincipal = SecurityContextHolder.getContext().getAuthentication();
// 获取grant_type client_id state state是可选的
MultiValueMap<String, String> parameters = OAuth2EndpointUtils.getParameters(request);
// scope (OPTIONAL)
// 验证 scope
String scope = parameters.getFirst(OAuth2ParameterNames.SCOPE);
if (StringUtils.hasText(scope) &&
parameters.get(OAuth2ParameterNames.SCOPE).size() != 1) {
OAuth2EndpointUtils.throwError(
OAuth2ErrorCodes.INVALID_REQUEST,
OAuth2ParameterNames.SCOPE,
OAuth2EndpointUtils.ACCESS_TOKEN_REQUEST_ERROR_URI);
}
Set<String> requestedScopes = null;
if (StringUtils.hasText(scope)) {
requestedScopes = new HashSet<>(
Arrays.asList(StringUtils.delimitedListToStringArray(scope, " ")));
}
Map<String, Object> additionalParameters = new HashMap<>();
parameters.forEach((key, value) -> {
if (!key.equals(OAuth2ParameterNames.GRANT_TYPE) &&
!key.equals(OAuth2ParameterNames.SCOPE)) {
additionalParameters.put(key, value.get(0));
}
});
return new OAuth2ClientCredentialsAuthenticationToken(
clientPrincipal, requestedScopes, additionalParameters);
}
}
(2)
public final class OAuth2ClientCredentialsAuthenticationProvider implements AuthenticationProvider {
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
OAuth2ClientCredentialsAuthenticationToken clientCredentialsAuthentication =
(OAuth2ClientCredentialsAuthenticationToken) authentication;
OAuth2ClientAuthenticationToken clientPrincipal =
getAuthenticatedClientElseThrowInvalidClient(clientCredentialsAuthentication);
RegisteredClient registeredClient = clientPrincipal.getRegisteredClient();
if (this.logger.isTraceEnabled()) {
this.logger.trace("Retrieved registered client");
}
// 再一次验证 该客户端AuthorizationGrantType 是否支持 client_credentials
if (!registeredClient.getAuthorizationGrantTypes().contains(AuthorizationGrantType.CLIENT_CREDENTIALS)) {
throw new OAuth2AuthenticationException(OAuth2ErrorCodes.UNAUTHORIZED_CLIENT);
}
// 获取请求的 scope
Set<String> authorizedScopes = Collections.emptySet();
if (!CollectionUtils.isEmpty(clientCredentialsAuthentication.getScopes())) {
for (String requestedScope : clientCredentialsAuthentication.getScopes()) {
if (!registeredClient.getScopes().contains(requestedScope)) {
throw new OAuth2AuthenticationException(OAuth2ErrorCodes.INVALID_SCOPE);
}
}
authorizedScopes = new LinkedHashSet<>(clientCredentialsAuthentication.getScopes());
}
if (this.logger.isTraceEnabled()) {
this.logger.trace("Validated token request parameters");
}
// 构建 OAuth2令牌上下文
// @formatter:off
OAuth2TokenContext tokenContext = DefaultOAuth2TokenContext.builder()
.registeredClient(registeredClient)
.principal(clientPrincipal)
.authorizationServerContext(AuthorizationServerContextHolder.getContext())
.authorizedScopes(authorizedScopes)
.tokenType(OAuth2TokenType.ACCESS_TOKEN)
.authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS)
.authorizationGrant(clientCredentialsAuthentication)
.build();
// @formatter:on
/**
* 生成 oauth2Token
* (3)
* 默认 是RegisteredClient .tokenSettings(TokenSettings.builder().accessTokenFormat(OAuth2TokenFormat.SELF_CONTAINED).build())
* 通过 DelegatingOAuth2TokenGenerator 获取JwtGenerator生成token 透明的token 他就是token
* (4)
* 如果RegisteredClient .tokenSettings(TokenSettings.builder().accessTokenFormat(OAuth2TokenFormat.REFERENCE).build())
* 通过 DelegatingOAuth2TokenGenerator 获取 OAuth2AccessTokenGenerator 生成token 不透明的token 他就是一串96长度的字符串
*/
OAuth2Token generatedAccessToken = this.tokenGenerator.generate(tokenContext);
if (generatedAccessToken == null) {
OAuth2Error error = new OAuth2Error(OAuth2ErrorCodes.SERVER_ERROR,
"The token generator failed to generate the access token.", ERROR_URI);
throw new OAuth2AuthenticationException(error);
}
if (this.logger.isTraceEnabled()) {
this.logger.trace("Generated access token");
}
OAuth2AccessToken accessToken = new OAuth2AccessToken(OAuth2AccessToken.TokenType.BEARER,
generatedAccessToken.getTokenValue(), generatedAccessToken.getIssuedAt(),
generatedAccessToken.getExpiresAt(), tokenContext.getAuthorizedScopes());
// @formatter:off
OAuth2Authorization.Builder authorizationBuilder = OAuth2Authorization.withRegisteredClient(registeredClient)
.principalName(clientPrincipal.getName())
.authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS)
.authorizedScopes(authorizedScopes);
// @formatter:on
if (generatedAccessToken instanceof ClaimAccessor) {
authorizationBuilder.token(accessToken, (metadata) ->
metadata.put(OAuth2Authorization.Token.CLAIMS_METADATA_NAME, ((ClaimAccessor) generatedAccessToken).getClaims()));
} else {
authorizationBuilder.accessToken(accessToken);
}
OAuth2Authorization authorization = authorizationBuilder.build();
// 保存token信息
this.authorizationService.save(authorization);
if (this.logger.isTraceEnabled()) {
this.logger.trace("Saved authorization");
// This log is kept separate for consistency with other providers
this.logger.trace("Authenticated token request");
}
return new OAuth2AccessTokenAuthenticationToken(registeredClient, clientPrincipal, accessToken);
}
}
(3)
public final class JwtGenerator implements OAuth2TokenGenerator<Jwt> {
@Nullable
@Override
public Jwt generate(OAuth2TokenContext context) {
//不支持 access_token 和id_token
if (context.getTokenType() == null ||
(!OAuth2TokenType.ACCESS_TOKEN.equals(context.getTokenType()) &&
!OidcParameterNames.ID_TOKEN.equals(context.getTokenType().getValue()))) {
return null;
}
// 支持 self-contained 透明的token 也就是 jwt token
if (OAuth2TokenType.ACCESS_TOKEN.equals(context.getTokenType()) &&
!OAuth2TokenFormat.SELF_CONTAINED.equals(context.getRegisteredClient().getTokenSettings().getAccessTokenFormat())) {
return null;
}
String issuer = null;
if (context.getAuthorizationServerContext() != null) {
issuer = context.getAuthorizationServerContext().getIssuer();
}
RegisteredClient registeredClient = context.getRegisteredClient();
Instant issuedAt = Instant.now();
Instant expiresAt;
JwsAlgorithm jwsAlgorithm = SignatureAlgorithm.RS256;
if (OidcParameterNames.ID_TOKEN.equals(context.getTokenType().getValue())) {
// TODO Allow configuration for ID Token time-to-live
expiresAt = issuedAt.plus(30, ChronoUnit.MINUTES);
if (registeredClient.getTokenSettings().getIdTokenSignatureAlgorithm() != null) {
jwsAlgorithm = registeredClient.getTokenSettings().getIdTokenSignatureAlgorithm();
}
} else {
expiresAt = issuedAt.plus(registeredClient.getTokenSettings().getAccessTokenTimeToLive());
}
// @formatter:off
JwtClaimsSet.Builder claimsBuilder = JwtClaimsSet.builder();
if (StringUtils.hasText(issuer)) {
claimsBuilder.issuer(issuer);
}
claimsBuilder
.subject(context.getPrincipal().getName())
.audience(Collections.singletonList(registeredClient.getClientId()))
.issuedAt(issuedAt)
.expiresAt(expiresAt);
if (OAuth2TokenType.ACCESS_TOKEN.equals(context.getTokenType())) {
claimsBuilder.notBefore(issuedAt);
if (!CollectionUtils.isEmpty(context.getAuthorizedScopes())) {
claimsBuilder.claim(OAuth2ParameterNames.SCOPE, context.getAuthorizedScopes());
}
} else if (OidcParameterNames.ID_TOKEN.equals(context.getTokenType().getValue())) {
claimsBuilder.claim(IdTokenClaimNames.AZP, registeredClient.getClientId());
if (AuthorizationGrantType.AUTHORIZATION_CODE.equals(context.getAuthorizationGrantType())) {
OAuth2AuthorizationRequest authorizationRequest = context.getAuthorization().getAttribute(
OAuth2AuthorizationRequest.class.getName());
String nonce = (String) authorizationRequest.getAdditionalParameters().get(OidcParameterNames.NONCE);
if (StringUtils.hasText(nonce)) {
claimsBuilder.claim(IdTokenClaimNames.NONCE, nonce);
}
}
SessionInformation sessionInformation = context.get(SessionInformation.class);
if (sessionInformation != null) {
claimsBuilder.claim("sid", sessionInformation.getSessionId());
claimsBuilder.claim(IdTokenClaimNames.AUTH_TIME, sessionInformation.getLastRequest());
}
}
// @formatter:on
JwsHeader.Builder jwsHeaderBuilder = JwsHeader.with(jwsAlgorithm);
if (this.jwtCustomizer != null) {
// @formatter:off
JwtEncodingContext.Builder jwtContextBuilder = JwtEncodingContext.with(jwsHeaderBuilder, claimsBuilder)
.registeredClient(context.getRegisteredClient())
.principal(context.getPrincipal())
.authorizationServerContext(context.getAuthorizationServerContext())
.authorizedScopes(context.getAuthorizedScopes())
.tokenType(context.getTokenType())
.authorizationGrantType(context.getAuthorizationGrantType());
if (context.getAuthorization() != null) {
jwtContextBuilder.authorization(context.getAuthorization());
}
if (context.getAuthorizationGrant() != null) {
jwtContextBuilder.authorizationGrant(context.getAuthorizationGrant());
}
if (OidcParameterNames.ID_TOKEN.equals(context.getTokenType().getValue())) {
SessionInformation sessionInformation = context.get(SessionInformation.class);
if (sessionInformation != null) {
jwtContextBuilder.put(SessionInformation.class, sessionInformation);
}
}
// @formatter:on
JwtEncodingContext jwtContext = jwtContextBuilder.build();
this.jwtCustomizer.customize(jwtContext);
}
JwsHeader jwsHeader = jwsHeaderBuilder.build();
JwtClaimsSet claims = claimsBuilder.build();
Jwt jwt = this.jwtEncoder.encode(JwtEncoderParameters.from(jwsHeader, claims));
return jwt;
}
}
(4)
public final class OAuth2AccessTokenGenerator implements OAuth2TokenGenerator<OAuth2AccessToken> {
@Nullable
@Override
public OAuth2AccessToken generate(OAuth2TokenContext context) {
if (!OAuth2TokenType.ACCESS_TOKEN.equals(context.getTokenType()) ||
!OAuth2TokenFormat.REFERENCE.equals(context.getRegisteredClient().getTokenSettings().getAccessTokenFormat())) {
return null;
}
String issuer = null;
if (context.getAuthorizationServerContext() != null) {
issuer = context.getAuthorizationServerContext().getIssuer();
}
RegisteredClient registeredClient = context.getRegisteredClient();
Instant issuedAt = Instant.now();
Instant expiresAt = issuedAt.plus(registeredClient.getTokenSettings().getAccessTokenTimeToLive());
// @formatter:off
OAuth2TokenClaimsSet.Builder claimsBuilder = OAuth2TokenClaimsSet.builder();
if (StringUtils.hasText(issuer)) {
claimsBuilder.issuer(issuer);
}
claimsBuilder
.subject(context.getPrincipal().getName())
.audience(Collections.singletonList(registeredClient.getClientId()))
.issuedAt(issuedAt)
.expiresAt(expiresAt)
.notBefore(issuedAt)
.id(UUID.randomUUID().toString());
if (!CollectionUtils.isEmpty(context.getAuthorizedScopes())) {
claimsBuilder.claim(OAuth2ParameterNames.SCOPE, context.getAuthorizedScopes());
}
// @formatter:on
if (this.accessTokenCustomizer != null) {
// @formatter:off
OAuth2TokenClaimsContext.Builder accessTokenContextBuilder = OAuth2TokenClaimsContext.with(claimsBuilder)
.registeredClient(context.getRegisteredClient())
.principal(context.getPrincipal())
.authorizationServerContext(context.getAuthorizationServerContext())
.authorizedScopes(context.getAuthorizedScopes())
.tokenType(context.getTokenType())
.authorizationGrantType(context.getAuthorizationGrantType());
if (context.getAuthorization() != null) {
accessTokenContextBuilder.authorization(context.getAuthorization());
}
if (context.getAuthorizationGrant() != null) {
accessTokenContextBuilder.authorizationGrant(context.getAuthorizationGrant());
}
// @formatter:on
OAuth2TokenClaimsContext accessTokenContext = accessTokenContextBuilder.build();
this.accessTokenCustomizer.customize(accessTokenContext);
}
OAuth2TokenClaimsSet accessTokenClaimsSet = claimsBuilder.build();
OAuth2AccessToken accessToken = new OAuth2AccessTokenClaims(OAuth2AccessToken.TokenType.BEARER,
this.accessTokenGenerator.generateKey(), accessTokenClaimsSet.getIssuedAt(), accessTokenClaimsSet.getExpiresAt(),
context.getAuthorizedScopes(), accessTokenClaimsSet.getClaims());
return accessToken;
}
}