Code Monkey home page Code Monkey logo

Comments (5)

thebordella avatar thebordella commented on June 1, 2024 2

@kamermans Amazing - thank you so much for this thorough example! I really appreciate it. And I understand it - my mistake was in the "new OAuth2Middleware" - I did not realize I could/should pass it both grant types in one call. That's the missing link! Thank you again so much for the explanation and creating this library.

from guzzle-oauth2-subscriber.

kamermans avatar kamermans commented on June 1, 2024 2

Sure thing! It took me a while to wrap my head around it again, but I'm glad I finally did. I'm updating the README so it is more clear to the next person :)

from guzzle-oauth2-subscriber.

kamermans avatar kamermans commented on June 1, 2024

Hi @thebordella, I agree with you, it sounds like the RefreshToken is not being used. I would need to be able to reproduce the issue myself to be able to easily debug it, but from what I can tell, you're using the refresh token part correctly. It looks like Google uses OAuth 2 with refresh tokens, so I'll see if I can test it out there, but it will take me at least a few days to find time.

In the meantime, perhaps you can come up with some shareable example that reproduces the problem?

from guzzle-oauth2-subscriber.

thebordella avatar thebordella commented on June 1, 2024

Thanks for your reply, @kamermans. One thing that confuses me is, in my latter code block, when new RefreshToken is assigned to $grant_type, how does it know where to get the persisted refresh token from? That is, it doesn't yet know about my custom persistence routine ... does it? This is unclear to me.

I added some debugging output to the OAuth2Handler.php script and it seems that "refreshTokenGrantType" remains null when my code block runs. When it detects that the auth token has expired and invokes requestNewAccessToken(), $this->refreshTokenGrantType is null. I'm not sure if that gives any clues...

from guzzle-oauth2-subscriber.

kamermans avatar kamermans commented on June 1, 2024

Hi @thebordella, sorry for the delayed response!

I have recreated a scenario similar to yours using the Google OAuth2 playground.

Please take a look at this script:

<?php
use kamermans\OAuth2\GrantType\RefreshToken;
use kamermans\OAuth2\GrantType\PasswordCredentials;
use kamermans\OAuth2\Persistence\TokenPersistenceInterface;
use kamermans\OAuth2\Token\TokenInterface;
use kamermans\OAuth2\OAuth2Middleware;
use GuzzleHttp\HandlerStack;

require_once __DIR__."/../guzzle_environments/6/vendor/autoload.php";

// Create a persistence provider that tells me what it's doing for debugging
class CustomTokenPersistence implements TokenPersistenceInterface {
    private $file = "/tmp/token.txt";
    public function saveToken(TokenInterface $token) {
        echo "Saving token: ".var_export($token, true)."\n";
        $value = $token->serialize();
        file_put_contents($this->file, json_encode($value));
    }
    public function restoreToken(TokenInterface $token) {
        $value = @file_get_contents($this->file);
        $value = $value === false? null: $token->unserialize(json_decode($value, true));
        echo "Restoring token: ".var_export($token, true)."\n";
        return $value;
    }
    public function deleteToken() {
        echo "Deleting token\n";
        @unlink($this->file);
    }
}

// Authorization client - this is used to request OAuth access tokens
$reauth_client = new GuzzleHttp\Client([
    // URL for access_token request
    'base_uri' => 'https://www.googleapis.com/oauth2/v4/token',
    // 'debug' => true,
]);

$reauth_config = [
    // PasswordCredentials credentials
    "username" => "my-username",
    "password" => "my-password",

    // RefreshToken credentials
    "client_id" => "my-client-id",

    // You probably don't have an existing refresh token, but if you do you can put it here,
    // otherwise just ignore this line or leave the value empty
    "refresh_token" => "existing-token-if-available",
];

$token_persistence = new CustomTokenPersistence();

// This grant type is used to get a new Access Token and Refresh Token when 
//  no valid Access Token or Refresh Token is available
$grant_type = new PasswordCredentials($reauth_client, $reauth_config);

// This grant type is used to get a new Access Token and Refresh Token when
//  only a valid Refresh Token is available
$refresh_grant_type = new RefreshToken($reauth_client, $reauth_config);

// Tell the middleware to use the two grant types
// Note that the second argument ($refresh_grant_type) gets stored in the OAuth2Handler
//  as $this->refreshTokenGrantType, which explains why it was previously null.
$oauth = new OAuth2Middleware($grant_type, $refresh_grant_type);

// Setup persistence
$oauth->setTokenPersistence($token_persistence);

// Add the middleware to the HandlerStack
$stack = HandlerStack::create();
$stack->push($oauth);

// This is the normal Guzzle client that you use in your application
$client = new GuzzleHttp\Client([
    'handler' => $stack,
    'auth'    => 'oauth',
]);

// This Google Cloud Platform endpoint will list all the projects you have access to
$endpoint_url = 'https://cloudresourcemanager.googleapis.com/v1/projects';
$response = $client->get($endpoint_url);
echo $response->getBody();

Note that the script above doesn't work correctly with Google Cloud Platform since they do not support the PasswordCredentials grant type, but I modified it to match your needs. If you do want to try this with GCP, go to the GCP OAuth 2.0 Playground, get a refresh token and put it in the $reauth_config above, or stick it into your persisted object manually.

The script above can be used to setup your Guzzle client. Here's how it works in your application:

  1. The first time you run it, if there is no access token or refresh token, it will use the PasswordCredentials to retrieve an access token. Assuming this token came with a refresh token, that token will be saved in the persistence provider with the access token.
  2. The next time the script is run, the access token and will be restored from persistence and will be used.
  3. Once the access token expires or is rejected by the server, the refresh token will be restored from persistence and the RefreshToken grant type will be used to obtain a new access token and refresh token, and these will be persisted together.

If you want to force the refresh token to be used the first time Guzzle is called after the script is run (without trying the old access token first), you could delete the contents of accessToken in the persisted array when the script starts - that will force the access token to be invalid and the refresh token will be used to get a new access token.

from guzzle-oauth2-subscriber.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.