272 String code =
formParams.getFirst(OAuth2Constants.CODE);
274 event.error(Errors.INVALID_CODE);
275 throw new CorsErrorResponseException(
cors, OAuthErrorException.INVALID_REQUEST,
"Missing parameter: " + OAuth2Constants.CODE, Response.Status.BAD_REQUEST);
278 ClientSessionCode.ParseResult<AuthenticatedClientSessionModel> parseResult = ClientSessionCode.parseResult(code, null,
session,
realm,
client,
event, AuthenticatedClientSessionModel.class);
279 if (parseResult.isAuthSessionNotFound() || parseResult.isIllegalHash()) {
280 AuthenticatedClientSessionModel clientSession = parseResult.getClientSession();
283 if (clientSession != null) {
284 clientSession.detachFromUserSession();
287 event.error(Errors.INVALID_CODE);
289 throw new CorsErrorResponseException(
cors, OAuthErrorException.INVALID_GRANT,
"Code not valid", Response.Status.BAD_REQUEST);
292 AuthenticatedClientSessionModel clientSession = parseResult.getClientSession();
294 if (parseResult.isExpiredToken()) {
295 event.error(Errors.EXPIRED_CODE);
296 throw new CorsErrorResponseException(
cors, OAuthErrorException.INVALID_GRANT,
"Code is expired", Response.Status.BAD_REQUEST);
299 UserSessionModel userSession = clientSession.getUserSession();
301 if (userSession == null) {
302 event.error(Errors.USER_SESSION_NOT_FOUND);
303 throw new CorsErrorResponseException(
cors, OAuthErrorException.INVALID_GRANT,
"User session not found", Response.Status.BAD_REQUEST);
307 UserModel user = userSession.getUser();
309 event.error(Errors.USER_NOT_FOUND);
310 throw new CorsErrorResponseException(
cors, OAuthErrorException.INVALID_GRANT,
"User not found", Response.Status.BAD_REQUEST);
313 event.user(userSession.getUser());
315 if (!user.isEnabled()) {
316 event.error(Errors.USER_DISABLED);
317 throw new CorsErrorResponseException(
cors, OAuthErrorException.INVALID_GRANT,
"User disabled", Response.Status.BAD_REQUEST);
320 String redirectUri = clientSession.getNote(OIDCLoginProtocol.REDIRECT_URI_PARAM);
321 String redirectUriParam =
formParams.getFirst(OAuth2Constants.REDIRECT_URI);
324 if (redirectUriParam != null && redirectUriParam.contains(
"session_state=") && !redirectUri.contains(
"session_state=")) {
325 redirectUriParam = KeycloakUriBuilder.fromUri(redirectUriParam)
326 .replaceQueryParam(OAuth2Constants.SESSION_STATE, null)
330 if (redirectUri != null && !redirectUri.equals(redirectUriParam)) {
331 event.error(Errors.INVALID_CODE);
332 throw new CorsErrorResponseException(
cors, OAuthErrorException.INVALID_GRANT,
"Incorrect redirect_uri", Response.Status.BAD_REQUEST);
336 event.error(Errors.INVALID_CODE);
337 throw new CorsErrorResponseException(
cors, OAuthErrorException.INVALID_GRANT,
"Auth error", Response.Status.BAD_REQUEST);
341 event.error(Errors.NOT_ALLOWED);
342 throw new CorsErrorResponseException(
cors, OAuthErrorException.INVALID_GRANT,
"Client not allowed to exchange code", Response.Status.BAD_REQUEST);
345 if (!AuthenticationManager.isSessionValid(
realm, userSession)) {
346 event.error(Errors.USER_SESSION_NOT_FOUND);
347 throw new CorsErrorResponseException(
cors, OAuthErrorException.INVALID_GRANT,
"Session not active", Response.Status.BAD_REQUEST);
351 String codeVerifier =
formParams.getFirst(OAuth2Constants.CODE_VERIFIER);
352 String codeChallenge = clientSession.getNote(OIDCLoginProtocol.CODE_CHALLENGE_PARAM);
353 String codeChallengeMethod = clientSession.getNote(OIDCLoginProtocol.CODE_CHALLENGE_METHOD_PARAM);
354 String authUserId = user.getId();
355 String authUsername = user.getUsername();
356 if (authUserId == null) {
357 authUserId =
"unknown";
359 if (authUsername == null) {
360 authUsername =
"unknown";
362 if (codeChallenge != null && codeVerifier == null) {
363 logger.warnf(
"PKCE code verifier not specified, authUserId = %s, authUsername = %s", authUserId, authUsername);
364 event.error(Errors.CODE_VERIFIER_MISSING);
365 throw new CorsErrorResponseException(
cors, OAuthErrorException.INVALID_GRANT,
"PKCE code verifier not specified", Response.Status.BAD_REQUEST);
368 if (codeChallenge != null) {
372 logger.infof(
"PKCE invalid code verifier");
373 event.error(Errors.INVALID_CODE_VERIFIER);
374 throw new CorsErrorResponseException(
cors, OAuthErrorException.INVALID_GRANT,
"PKCE invalid code verifier", Response.Status.BAD_REQUEST);
377 logger.debugf(
"PKCE supporting Client, codeVerifier = %s", codeVerifier);
378 String codeVerifierEncoded = codeVerifier;
382 if (codeChallengeMethod != null && codeChallengeMethod.equals(OAuth2Constants.PKCE_METHOD_S256)) {
383 logger.debugf(
"PKCE codeChallengeMethod = %s", codeChallengeMethod);
386 logger.debug(
"PKCE codeChallengeMethod is plain");
387 codeVerifierEncoded = codeVerifier;
389 }
catch (Exception nae) {
390 logger.infof(
"PKCE code verification failed, not supported algorithm specified");
391 event.error(Errors.PKCE_VERIFICATION_FAILED);
392 throw new CorsErrorResponseException(
cors, OAuthErrorException.INVALID_GRANT,
"PKCE code verification failed, not supported algorithm specified", Response.Status.BAD_REQUEST);
394 if (!codeChallenge.equals(codeVerifierEncoded)) {
395 logger.warnf(
"PKCE verification failed. authUserId = %s, authUsername = %s", authUserId, authUsername);
396 event.error(Errors.PKCE_VERIFICATION_FAILED);
397 throw new CorsErrorResponseException(
cors, OAuthErrorException.INVALID_GRANT,
"PKCE verification failed", Response.Status.BAD_REQUEST);
399 logger.debugf(
"PKCE verification success. codeVerifierEncoded = %s, codeChallenge = %s", codeVerifierEncoded, codeChallenge);
409 String scopeParam = clientSession.getNote(OAuth2Constants.SCOPE);
410 Set<ClientScopeModel> clientScopes = TokenManager.getRequestedClientScopes(scopeParam,
client);
411 if (!TokenManager.verifyConsentStillAvailable(
session, user,
client, clientScopes)) {
412 event.error(Errors.NOT_ALLOWED);
413 throw new CorsErrorResponseException(
cors, OAuthErrorException.INVALID_SCOPE,
"Client no longer has requested consent from user", Response.Status.BAD_REQUEST);
416 ClientSessionContext clientSessionCtx = DefaultClientSessionContext.fromClientSessionAndClientScopes(clientSession, clientScopes);
422 .generateRefreshToken();
426 if (OIDCAdvancedConfigWrapper.fromClientModel(
client).isUseMtlsHokToken()) {
427 AccessToken.CertConf certConf = MtlsHoKTokenUtil.bindTokenWithClientCertificate(
request,
session);
428 if (certConf != null) {
429 responseBuilder.getAccessToken().setCertConf(certConf);
430 responseBuilder.getRefreshToken().setCertConf(certConf);
432 event.error(Errors.INVALID_REQUEST);
433 throw new CorsErrorResponseException(
cors, OAuthErrorException.INVALID_REQUEST,
"Client Certification missing for MTLS HoK Token Binding", Response.Status.BAD_REQUEST);
437 if (TokenUtil.isOIDCRequest(scopeParam)) {
438 responseBuilder.generateIDToken();
441 AccessTokenResponse res = responseBuilder.build();
445 return cors.
builder(Response.ok(res).type(MediaType.APPLICATION_JSON_TYPE)).build();
final EventBuilder event
Definition: TokenEndpoint.java:144
boolean isStandardFlowEnabled()
boolean isValidPkceCodeVerifier(String codeVerifier)
Definition: TokenEndpoint.java:1144
void updateClientSession(AuthenticatedClientSessionModel clientSession)
Definition: TokenEndpoint.java:484
MultivaluedMap< String, String > formParams
Definition: TokenEndpoint.java:116
HttpRequest request
Definition: TokenEndpoint.java:131
Cors cors
Definition: TokenEndpoint.java:150
ClientModel client
Definition: TokenEndpoint.java:117
final TokenManager tokenManager
Definition: TokenEndpoint.java:142
final RealmModel realm
Definition: TokenEndpoint.java:143
static final Logger logger
Definition: TokenEndpoint.java:115
ResponseBuilder builder
Definition: Cors.java:61
KeycloakSession session
Definition: TokenEndpoint.java:128
String generateS256CodeChallenge(String codeVerifier)
Definition: TokenEndpoint.java:1158
void updateUserSessionFromClientAuth(UserSessionModel userSession)
Definition: TokenEndpoint.java:510