Problem/Motivation

This module has some issues with the authorization_code grant type.

1. \Drupal\oauth2_client\Service\Grant\AuthorizationCodeGrantService::getAccessToken doesn't return an access token:

// Oauth2ClientService::getAuthorizationCodeAccessToken 
...
    if (empty($access_token)) {
      $access_token = $this->grantServices['authorization_code']->getAccessToken($clientId); // Nothing is returned here!
    }
...

2. The access token is stored in the state, which is shared by all subsequent callers.

3. This doesn't work for anonymous users, because their sessions aren't saved when we redirect to the authorization url. This leads to failure every time on the CSRF check:

...
    elseif (!$this->currentRequest->get('state') || $this->currentRequest->get('state') !== $this->tempstore->get('oauth2_client_state-' . $clientId)) {
        // Potential CSRF attack. Bail out.
        $this->tempstore->delete('oauth2_client_state-' . $clientId);
...

Steps to reproduce

Create a plugin with grant_type = "authorization_code"

Create a simple controller:

    $accessToken = \Drupal::service('oauth2_client.service')->getAccessToken('my-client-id');
    $token = $accessToken->getToken();
    return new Response($token);

1. Load: (Should correctly route to the authentication provider and back.) First time should be: Error: Call to a member function getToken() on null

2. Reload: It's now pulling from state, so it should work. However, it will now provide that access token to any user. 😬

3. Clear the state variable, log out, try to get an access token.

Proposed resolution

1. Return $accessToken.
2. Store token(s) in Drupal's tempstore instead of state for authorization_code requests.
3. Save the session before redirecting.

CommentFileSizeAuthor
#2 3182425.patch7.04 KBzerbash

Comments

zerbash created an issue. See original summary.

zerbash’s picture

StatusFileSize
new7.04 KB
fathershawn’s picture

It seems to me that site interaction with another service as an api shared sitewide is the most common use case. However, the storage change you are proposing here could be accomplished for a particular site by decorating oauth2_client.service.grant.authorization_code and overriding the inherited \Drupal\oauth2_client\Service\Grant\Oauth2ClientGrantServiceBase::storeAccessToken in the decorator class.

Linking to a blog post on how that works for other users who come across this issue: Drupal 8: Service Decorators

zerbash’s picture

I agree that that's the most common case, but every third-party service we do site-wide interaction with provides an API key -- they know who we are, we know who they are, no need for OAuth. I would venture to guess that the most common use of this module would be to request services on behalf of individual users. But I only have a sample set of two (my case, your case), so I'm certainly not speaking with any authority!

fathershawn’s picture

Status: Active » Closed (duplicate)