bshaffer / oauth2-server-php

A library for implementing an OAuth2 Server in php
http://bshaffer.github.io/oauth2-server-php-docs
MIT License
3.26k stars 953 forks source link

Grant Refresh Token not returning a new refresh token #700

Open uteq opened 8 years ago

uteq commented 8 years ago

I have set up a small wrapper for the OAuth2\Server so I won't have to configure the Server to my needs everytime i need to initiate a new server. This is working, I get my access token and a refresh token using the User Credentials grant.

{"access_token":"eb316dadb673fa3b48f4c664d2f6a8b508d60f36","expires_in":86400,"token_type":"Bearer","scope":null,"refresh_token":"1921807c2868d4c576cfe6e663ee087a68f46b39"}

These are my configurations:

$config = [
        'access_lifetime' => 60*60*24, // 1 day
        'refresh_token_lifetime' => 60*60*24*28, // 28 days
        'always_issue_new_refresh_token' => true,
        'unset_refresh_token_after_use' => false
    ];

Then I use the Refresh Token grant and get the following json:

{"access_token":"083335bc185b1d3c3b711910aedc33b53135eb40","expires_in":86400,"token_type":"Bearer","scope":null}

If I'm right, according to my config this approach should provide me with a refresh_token as well. And if I'm right it should not delete the refresh token after use, this is happening as well. Also tried leaving the unset_refresh_token_after_use on default.

Also when I print the OAuth2\Server class you can see the config is set properly:

OAuth2\Server Object
(
    [response:protected] => 
    [config:protected] => Array
        (
            [use_jwt_access_tokens] => 
            [store_encrypted_token_string] => 1
            [use_openid_connect] => 
            [id_lifetime] => 3600
            [access_lifetime] => 86400
            [www_realm] => Service
            [token_param_name] => access_token
            [token_bearer_header_name] => Bearer
            [enforce_state] => 1
            [require_exact_redirect_uri] => 1
            [allow_implicit] => 
            [allow_credentials_in_request_body] => 1
            [allow_public_clients] => 1
            [always_issue_new_refresh_token] => 1
            [unset_refresh_token_after_use] => 
            [refresh_token_lifetime] => 2419200
        )

What might this be?

afilippov1985 commented 8 years ago

What storage adapter do you use?

uteq commented 8 years ago

OAuth2\Storage\PDO

afilippov1985 commented 8 years ago

Show you code where you initialize OAuth2\Server class

$server = new OAuth2\Server(...)
$server->addGrantType(...)
uteq commented 8 years ago

I created a little abstraction layer for the grant types, so this basically is my code:

$dsn = sprintf('%s:dbname=%s;host=%s', 'mysql', 'database', 'localhost');
$username = 'username';
$password = 'password';

$storage = new OAuth2\Storage\Pdo(
    [
        'dsn' => $dsn,
        'username' => $username,
        'password' => $password,
    ]
);

$server = new OAuth2\Server($storage, [
        'access_lifetime' => 86400, // 1 day
        'refresh_token_lifetime' => 2419200, // 28 days
        'always_issue_new_refresh_token' => true,
        'unset_refresh_token_after_use' => false
]);

$grantTypes = [
    'user_credentials' => 'UserCredentials',
    'client_credentials' => 'ClientCredentials',
    'authorization_code' => 'AuthorizationCode',
    'refresh_token' => 'RefreshToken'
];

$serverGrants = [
    'user_credentials',
    'refresh_token',
];

foreach ($serverGrants as $grant) {
        if (isset($grantTypes[$grant])) {
            $class = 'OAuth2\\GrantType\\'. $grantTypes[$grant];
            $grantClass = new $class($storage);

            $server->addGrantType($grantClass);
        } else {
            throw new \Exception("Grant type ". $grant ." could not be added to server. It does not exist. Please use on of these". print_r($grantTypes));
        }
}

Running PHP version 5.6

afilippov1985 commented 8 years ago

Instantiated grant types don't inherit server config So always_issue_new_refresh_token parameter does not pass to OAuth2\GrantTypeRefreshToken

Change this $grantClass = new $class($storage); to this

$config = [
    'access_lifetime' => 86400, // 1 day
    'refresh_token_lifetime' => 2419200, // 28 days
    'always_issue_new_refresh_token' => true,
    'unset_refresh_token_after_use' => false
];
.......
$grantClass = new $class($storage, $config);
afilippov1985 commented 8 years ago

even better would be to write it this way

$server = new OAuth2\Server($storage, [
    'access_lifetime' => 86400, // 1 day
    'refresh_token_lifetime' => 2419200, // 28 days
]);

$server->addGrantType(new OAuth2\GrantType\UserCredentials($server->getStorage('authorization_code')));
$server->addGrantType(new OAuth2\GrantType\RefreshToken($server->getStorage('refresh_token'), ['always_issue_new_refresh_token' => true]));
uteq commented 8 years ago

You're awesome! That worked!

pjebs commented 8 years ago

@bshaffer The workaround works but is this a bug?

@Ganganation If you were to add the grant types via the server constructor (optional 3rd parameter), then the server will create a default refreshToken grant type instance with your original $config parameters passing through to it.

jahrralf commented 7 years ago

Well, I experiences some trouble here. My server, without always_issue_new_refresh_token = true, discarded the refresh_token after successfully renewing the access_token with a refresh_token. This is kind of weird, because afterwards you cannot ask for a new access_token again although the refresh_token would be valid for a few more days.

ickyfoot commented 7 years ago

Great stuff, afilippov1985, many thanks!

jokabuyasina commented 7 years ago

@ jahrralf I have the issue I tried your solution, still not returning a new refresh token. This is my server.php

$dsn = 'mysql:dbname=;host=localhost'; $username = ''; $password = '';

// Autoloading (composer is preferred, but for this example let's just do this) require_once('oauth2-server-php/src/OAuth2/Autoloader.php'); OAuth2\Autoloader::register();

// $dsn is the Data Source Name for your database, for exmaple "mysql:dbname=my_oauth2_db;host=localhost" $storage = new OAuth2\Storage\Pdo(array('dsn' => $dsn, 'username' => $username, 'password' => $password));

$server = new OAuth2\Server($storage, [ 'access_lifetime' => 1209600, 'refresh_token_lifetime' => 2700000, 'always_issue_new_refresh_token' => true, 'unset_refresh_token_after_use' => false ]);

$server->addGrantType(new OAuth2\GrantType\RefreshToken($storage)); // Add the "Client Credentials" grant type (it is the simplest of the grant types) $server->addGrantType(new OAuth2\GrantType\ClientCredentials($storage));

// Add the "Authorization Code" grant type (this is where the oauth magic happens) $server->addGrantType(new OAuth2\GrantType\AuthorizationCode($storage));

pYr0x commented 7 years ago

maybe the docs should be clear about the config. the configs that can be set by new \OAuth2\Server() only get used by the method getDefaultGrantTypes(). this method only gets called if you provide no storage array to the server. see code:

...
if (0 == count($this->grantTypes)) {
  $this->grantTypes = $this->getDefaultGrantTypes();
}
...

the docs should mention that if you use addGrantType() or add grant types to the server, the config that is also passed to the server constructor are not used for the grant types you added manually!

summary: this is not working:

        $pdoStorage = new \OAuth2\Storage\Pdo($pdoConnection);
        $userCredentialStorage = new \twentytwo\extensions\OAuth\UserCredentialStorage($pdoConnection);
        $accessTokenStorage = new \twentytwo\extensions\OAuth\AccessTokenStorage($pdoConnection);

        $app['oauth.server'] = new \OAuth2\Server([
            // storages
            'access_token' => $accessTokenStorage,
            'refresh_token' => $pdoStorage,
            'client' => $pdoStorage,
            'scope' => $pdoStorage,
            'user_credentials' => $userCredentialStorage
        ], [
            // configs
            'always_issue_new_refresh_token' => true,
            'refresh_token_lifetime'         => 2419200
        ], [
            // granttypes
            'password' => new \twentytwo\extensions\OAuth\UserCredentials($userCredentialStorage),
            'refresh_token' => new \OAuth2\GrantType\RefreshToken($pdoStorage)
        ]);

and should be:

        $pdoStorage = new \OAuth2\Storage\Pdo($pdoConnection);
        $userCredentialStorage = new \twentytwo\extensions\OAuth\UserCredentialStorage($pdoConnection);
        $accessTokenStorage = new \twentytwo\extensions\OAuth\AccessTokenStorage($pdoConnection);

        $app['oauth.server'] = new \OAuth2\Server([
            // storages
            'access_token' => $accessTokenStorage,
            'refresh_token' => $pdoStorage,
            'client' => $pdoStorage,
            'scope' => $pdoStorage,
            'user_credentials' => $userCredentialStorage
        ], [
            // configs

        ], [
            // granttypes
            'password' => new \twentytwo\extensions\OAuth\UserCredentials($userCredentialStorage),
            'refresh_token' => new \OAuth2\GrantType\RefreshToken($pdoStorage, ['always_issue_new_refresh_token' => true])
        ], [
            // response types
            'token' => new \OAuth2\ResponseType\AccessToken($accessTokenStorage, $pdoStorage, ['refresh_token_lifetime' => 2419200])
        ]);