/** {@inheritDoc} */
  public AuthorizationCode readAuthorizationCode(OAuth2Request request, String code)
      throws InvalidGrantException, ServerException, NotFoundException {
    if (logger.messageEnabled()) {
      logger.message("Reading Authorization code: " + code);
    }
    final JsonValue token;

    // Read from CTS
    try {
      token = tokenStore.read(code);
    } catch (CoreTokenException e) {
      logger.error("Unable to read authorization code corresponding to id: " + code, e);
      throw new ServerException("Could not read token from CTS: " + e.getMessage());
    }

    if (token == null) {
      logger.error("Unable to read authorization code corresponding to id: " + code);
      throw new InvalidGrantException("The provided access grant is invalid, expired, or revoked.");
    }

    OpenAMAuthorizationCode authorizationCode = new OpenAMAuthorizationCode(token);
    validateTokenRealm(authorizationCode.getRealm(), request);

    request.setToken(AuthorizationCode.class, authorizationCode);
    return authorizationCode;
  }
  /** {@inheritDoc} */
  public AuthorizationCode createAuthorizationCode(
      Set<String> scope,
      ResourceOwner resourceOwner,
      String clientId,
      String redirectUri,
      String nonce,
      OAuth2Request request,
      String codeChallenge,
      String codeChallengeMethod)
      throws ServerException, NotFoundException {

    logger.message("DefaultOAuthTokenStoreImpl::Creating Authorization code");

    OpenIdConnectClientRegistration clientRegistration = getClientRegistration(clientId, request);

    final OAuth2ProviderSettings providerSettings = providerSettingsFactory.get(request);
    final String code = UUID.randomUUID().toString();

    long expiryTime = 0;
    if (clientRegistration == null) {
      expiryTime = providerSettings.getAuthorizationCodeLifetime() + System.currentTimeMillis();
    } else {
      expiryTime =
          clientRegistration.getAuthorizationCodeLifeTime(providerSettings)
              + System.currentTimeMillis();
    }

    final String ssoTokenId = getSsoTokenId(request);

    final OpenAMAuthorizationCode authorizationCode =
        new OpenAMAuthorizationCode(
            code,
            resourceOwner.getId(),
            clientId,
            redirectUri,
            scope,
            getClaimsFromRequest(request),
            expiryTime,
            nonce,
            realmNormaliser.normalise(request.<String>getParameter(REALM)),
            getAuthModulesFromSSOToken(request),
            getAuthenticationContextClassReferenceFromRequest(request),
            ssoTokenId,
            codeChallenge,
            codeChallengeMethod);

    // Store in CTS
    try {
      tokenStore.create(authorizationCode);
      if (auditLogger.isAuditLogEnabled()) {
        String[] obs = {"CREATED_AUTHORIZATION_CODE", authorizationCode.toString()};
        auditLogger.logAccessMessage("CREATED_AUTHORIZATION_CODE", obs, null);
      }
    } catch (CoreTokenException e) {
      if (auditLogger.isAuditLogEnabled()) {
        String[] obs = {"FAILED_CREATE_AUTHORIZATION_CODE", authorizationCode.toString()};
        auditLogger.logErrorMessage("FAILED_CREATE_AUTHORIZATION_CODE", obs, null);
      }
      logger.error("Unable to create authorization code " + authorizationCode.getTokenInfo(), e);
      throw new ServerException("Could not create token in CTS");
    }

    request.setToken(AuthorizationCode.class, authorizationCode);

    return authorizationCode;
  }