docs: public AccessToken blockingIssueAccessToken(FullHttpRequest req) throws OAuthException {
          TokenRequest tokenRequest = TokenRequest.create(req);
          tokenRequest.validate();
          // check valid client_id, client_secret and status of the client app should be active
          if (!isActiveClient(tokenRequest.getClientId(), tokenRequest.getClientSecret()).blockingGet()) {
              throw new OAuthException(ResponseBuilder.INVALID_CLIENT_CREDENTIALS, HttpResponseStatus.BAD_REQUEST);
          }
  
          AccessToken accessToken = null;
          if (TokenRequest.AUTHORIZATION_CODE.equals(tokenRequest.getGrantType())) {
              AuthCode authCode = findAuthCode(tokenRequest).blockingGet();
              // TODO: REVISIT: Move client_id check to db query
              if (authCode != null) {
                  if (!tokenRequest.getClientId().equals(authCode.getClientId())) {
                      throw new OAuthException(ResponseBuilder.INVALID_CLIENT_ID, HttpResponseStatus.BAD_REQUEST);
                  }
                  if (authCode.getRedirectUri() != null
                          && !tokenRequest.getRedirectUri().equals(authCode.getRedirectUri())) {
                      throw new OAuthException(ResponseBuilder.INVALID_REDIRECT_URI, HttpResponseStatus.BAD_REQUEST);
                  } else {
                      // invalidate the auth code
                      db.updateAuthCodeValidStatus(authCode.getCode(), false).blockingAwait();
                      accessToken = new AccessToken(TOKEN_TYPE_BEARER, getExpiresIn(TokenRequest.PASSWORD, authCode.getScope()),
                              authCode.getScope(), getExpiresIn(TokenRequest.REFRESH_TOKEN, authCode.getScope()));
                      accessToken.setUserId(authCode.getUserId());
                      accessToken.setClientId(authCode.getClientId());
                      accessToken.setCodeId(authCode.getId());
                      db.storeAccessToken(accessToken).blockingAwait();
                  }
              } else {
                  throw new OAuthException(ResponseBuilder.INVALID_AUTH_CODE, HttpResponseStatus.BAD_REQUEST);
              }
          } else if (TokenRequest.REFRESH_TOKEN.equals(tokenRequest.getGrantType())) {
              accessToken = db.findAccessTokenByRefreshToken(tokenRequest.getRefreshToken(), tokenRequest.getClientId()).blockingGet();
              if (accessToken != null) {
                  if (!accessToken.refreshTokenExpired()) {
                      String validScope;
                      if (tokenRequest.getScope() != null) {
                          if (scopeService.scopeAllowed(tokenRequest.getScope(), accessToken.getScope())) {
                              validScope = tokenRequest.getScope();
                          } else {
                              throw new OAuthException(ResponseBuilder.SCOPE_NOK_MESSAGE, HttpResponseStatus.BAD_REQUEST);
                          }
                      } else {
                          validScope = accessToken.getScope();
                      }
                      db.updateAccessTokenValidStatus(accessToken.getToken(), false).blockingAwait();
                      AccessToken newAccessToken = new AccessToken(TOKEN_TYPE_BEARER, getExpiresIn(TokenRequest.PASSWORD,
                              validScope), validScope, accessToken.getRefreshToken(), accessToken.getRefreshExpiresIn());
                      newAccessToken.setUserId(accessToken.getUserId());
                      newAccessToken.setDetails(accessToken.getDetails());
                      newAccessToken.setClientId(accessToken.getClientId());
                      db.storeAccessToken(newAccessToken).blockingAwait();
                      db.removeAccessToken(accessToken.getToken()).blockingAwait();
                      return newAccessToken;
                  } else {
                      db.removeAccessToken(accessToken.getToken()).blockingAwait();
                      throw new OAuthException(ResponseBuilder.INVALID_REFRESH_TOKEN, HttpResponseStatus.BAD_REQUEST);
                  }
              } else {
                  throw new OAuthException(ResponseBuilder.INVALID_REFRESH_TOKEN, HttpResponseStatus.BAD_REQUEST);
              }
          } else if (TokenRequest.CLIENT_CREDENTIALS.equals(tokenRequest.getGrantType())) {
              ClientCredentials clientCredentials = db.findClientCredentials(tokenRequest.getClientId()).blockingGet();
              String scope = scopeService.getValidScopeByScope(tokenRequest.getScope(), clientCredentials.getScope());
              if (scope == null) {
                  throw new OAuthException(ResponseBuilder.SCOPE_NOK_MESSAGE, HttpResponseStatus.BAD_REQUEST);
              }
  
              accessToken = new AccessToken(TOKEN_TYPE_BEARER, getExpiresIn(TokenRequest.CLIENT_CREDENTIALS, scope),
                      scope, false, null);
              accessToken.setClientId(tokenRequest.getClientId());
              Map<String, String> applicationDetails = clientCredentials.getApplicationDetails();
              if ((applicationDetails != null) && (applicationDetails.size() > 0)) {
                  accessToken.setDetails(applicationDetails); // For backward compatibility
                  accessToken.setApplicationDetails(applicationDetails);
              }
              db.storeAccessToken(accessToken).blockingAwait();
          } else if (TokenRequest.PASSWORD.equals(tokenRequest.getGrantType())) {
              ClientCredentials clientCredentials = db.findClientCredentials(tokenRequest.getClientId()).blockingGet();
              String scope = scopeService.getValidScopeByScope(tokenRequest.getScope(), clientCredentials.getScope());
              if (scope == null) {
                  throw new OAuthException(ResponseBuilder.SCOPE_NOK_MESSAGE, HttpResponseStatus.BAD_REQUEST);
              }
  
              try {
                  UserDetails userDetails = authenticateUser(tokenRequest.getUsername(), tokenRequest.getPassword(), req);
                  if (userDetails != null && userDetails.getUserId() != null) {
                      accessToken = new AccessToken(TOKEN_TYPE_BEARER, getExpiresIn(TokenRequest.PASSWORD, scope), scope,
                              getExpiresIn(TokenRequest.REFRESH_TOKEN, scope));
                      accessToken.setUserId(userDetails.getUserId());
                      accessToken.setDetails(userDetails.getDetails());
                      accessToken.setClientId(tokenRequest.getClientId());
                      accessToken.setApplicationDetails(clientCredentials.getApplicationDetails());
                      db.storeAccessToken(accessToken).blockingAwait();
                  } else {
                      throw new OAuthException(ResponseBuilder.INVALID_USERNAME_PASSWORD, HttpResponseStatus.UNAUTHORIZED);
                  }
              } catch (AuthenticationException e) {
                  // in case some custom response should be returned other than HTTP 401
                  // for instance, if the user authentication requires more user details as a subsequent step
                  if (e.getResponse() != null) {
                      String responseContent = ((FullHttpResponse) (e.getResponse())).content().toString(CharsetUtil.UTF_8);
                      throw new OAuthException(e, responseContent, e.getResponse().getStatus());
                  } else {
                      LOG.error("Cannot authenticate user", e);
                      throw new OAuthException(e, ResponseBuilder.CANNOT_AUTHENTICATE_USER, HttpResponseStatus.UNAUTHORIZED); // NOSONAR
                  }
              }
          } else if (tokenRequest.getGrantType().equals(OAuthConfig.getCustomGrantType())) {
              String scope = scopeService.getValidScope(tokenRequest.getScope(), tokenRequest.getClientId()).blockingGet();
              if (scope == null) {
                  throw new OAuthException(ResponseBuilder.SCOPE_NOK_MESSAGE, HttpResponseStatus.BAD_REQUEST);
              }
              try {
                  accessToken = new AccessToken(TOKEN_TYPE_BEARER, getExpiresIn(TokenRequest.PASSWORD, scope), scope,
                          getExpiresIn(TokenRequest.REFRESH_TOKEN, scope));
                  accessToken.setClientId(tokenRequest.getClientId());
                  UserDetails userDetails = callCustomGrantTypeHandler(req);
                  if (userDetails != null && userDetails.getUserId() != null) {
                      accessToken.setUserId(userDetails.getUserId());
                      accessToken.setDetails(userDetails.getDetails());
                  }
                  db.storeAccessToken(accessToken).blockingAwait();
              } catch (AuthenticationException e) {
                  LOG.error("Cannot authenticate user", e);
                  throw new OAuthException(e, ResponseBuilder.CANNOT_AUTHENTICATE_USER, HttpResponseStatus.UNAUTHORIZED);
              }
          }
          return accessToken;
      }