View the complete documentation
bshaffer / oauth2-server-php Goto Github PK
View Code? Open in Web Editor NEWA library for implementing an OAuth2 Server in php
Home Page: http://bshaffer.github.io/oauth2-server-php-docs
License: MIT License
A library for implementing an OAuth2 Server in php
Home Page: http://bshaffer.github.io/oauth2-server-php-docs
License: MIT License
View the complete documentation
Add the three main request types to the readme, and outline the main methods involved. Also, link to a blog post/tutorial once created
My "user" table doesn't have primary column named "user_id" , it is called "id" . Right now i have changed query
SELECT * from user_table
to
SELECT *, id as user_id from user_table
so that user_id is updated correctly in in access_token table. It woud be helpful if we can via configuration map the column name for "user" table.
As in the specs, "code" is application/x-www-form-urlencoded in the authorization code request, so POST data. But the library is checking against GET.
Similar to kriswallsmith/Buzz, we'd like to submit the response as part of the request. This will make for a much cleaner Controller
layer, and also allow for dependency injection, which is really not currently possible without undergoing a massive amount of pain.
In PR #25, we have support for JWT as Authorization Grants
Now, we need support for JWT as Client Authentication
The implicit flow is less secure than the authorization code flow, neither the spec or any other resources attempt to hide that.
A potential problem revolves around mistakenly using OAuth2 not just for authorization, but for authentication as well.
An attack is described in http://homakov.blogspot.com/2012/08/oauth2-one-accesstoken-to-rule-them-all.html
and can be resolved by implementing an additional call to validate the access token after it has been received (send the token and a client id, get a status and a list of scopes back).
I think it would make sense to have a note in the README about this.
As the people providing the library (and Drupal integration in my case), we are responsible if people shoot themselves in the foot with it.
Another related resource: http://homakov.blogspot.com/2013/03/oauth1-oauth2-oauth.html
handleAuthorizeRequest() in OAuth2_Controller_AuthorizeController does not set $this->response before returning a successful authorization redirect response. A subsequent call to getResponse() will return NULL.
When the Resource Owner clicks on the 'Authorize' Button the previous queryString will be added to the url and the form is sent with POST to the server.
template:
<form action="{{ path('oauth2_authorize_post') ~ '?' ~ app.request.queryString }}" method="post">
So depending on the REQUEST_METHOD does not work in this case as the scope will be in the GET parameters.
https://github.com/bshaffer/oauth2-server-php/blob/develop/src/OAuth2/Scope.php#L51-L54
Hi Brent, Currently rolling out some Oauth2 stuff here for various GIS end applications. We do have our own rudimentary Oauth2 in house server but I'm looking to ditch this in favour of something a little further down the development line. As all our stuff is GIS we're very much postgres/postgis folks. I'm immediately hitting some incompatibilities when using PDO/pgsql with your stuff, initially in data escaping in SQL commands. What I'm going to do is update some of this stuff to use data binding to fix these issues and at the same time improve the SQL injection vulnerabilities. Are you interested in getting these changes into your source or am I heading off alone down my own fork?
Ta,
Andy Shelley.
I just came across your library and would like to implement it into my application to support OAuth 2.
I am looking to implement 2-legged OAuth for server-to-server authorization which means that I won't have to send a token with each request to my application's API.
Edit: Looks like the above applies to OAuth 1. In OAuth 2, all I see is an Authorization: OAuth ya29.afa3fsadfaf
header.
I am still looking through the source, but does this library support 2-legged OAuth (processing request without a token)? If so, how is it implemented?
Sorry but I can not understand what is the right database structure to use!
This class OAuth2_Storage_Pdo understand that you must have 4 tables:
I understand that the getAccessTokenData exists to return the Access Token, however I'm looking for a way to get ALL of the Access Token Data as the name suggests. Is there a way to do that I don't see? Or could the function be renamed to something closer to what the function actually returns, i.e. just getAccessToken?
In testing OAuth2_Storage_RefreshTokenInterface, a refresh_token is being returned when using the Client Credentials Grant. It should probably be removed from this grant type to better adhere to http://tools.ietf.org/html/rfc6749#section-4.4.3
4.4.3. Access Token Response
If the access token request is valid and authorized, the
authorization server issues an access token as described in
Section 5.1. A refresh token SHOULD NOT be included.
Code from an example call:
$storage = new PDO('mysql:dbname=account;host=localhost', 'oauth', 'oauth');
$server = new OAuth2_Server($storage);
$server->addGrantType(new OAuth2_GrantType_ClientCredentials($storage));
$request = OAuth2_Request::createFromGlobals();
$token = $server->grantAccessToken($request)
echo json_encode($token);
With the following response:
{"access_token":"ce7f0d2cce0e9dc0e6f4d6ed24c5def1afdea5c6","expires_in":3600,"token_type":"bearer","scope":null,"refresh_token":"a7db8c2b2bdf4319d6233db394979e89c5809ffe"}
Was just reading about SAML and found that they can also be used to authenticate and authorize OAuth 2 tokens.
The flow seems to be quite similar to how JWT works, so we should be quite familiar with it.
IETF Draft: http://tools.ietf.org/html/draft-ietf-oauth-saml2-bearer-16
This is not a must have or anything urgent, but would be nice to implement when any of us have some extra time. The flow should be very similar if not identical to the flow for JWT tokens, so it shouldn't be too complicated.
Interestingly, it also has a client authentication mode similar to JWT's client authentication in #27, so perhaps we can look at a general way to abstract the AuthorizationCode
grant type to support JWTs and SAML.
The specified array keys defined in the interface is inconsistent with the unit tests.
Example interface:
OAuth2_Storage_AuthorizationCodeInterface::getAuthorizationCode
/**
* @return
* An associative array as below, and NULL if the code is invalid:
* - client_id: Stored client identifier.
* - redirect_uri: Stored redirect URI.
* - expires: Stored expiration in unix timestamp.
* - scope: (optional) Stored scope values in space-separated string.
*/
Unit test:
OAuth2_Storage_PdoTest::testSetAuthorizationCode
$success = $storage->setAuthorizationCode('newcode', 'client ID', 'SOMEUSERID', 'http://adobe.com', time() + 20);
$this->assertTrue($success);
$code = $storage->getAuthorizationCode('newcode');
$this->assertNotNull($code);
$this->arrayHasKey('access_token', $code);
$this->arrayHasKey('client_id', $code);
The test above has several issues.
I'd be willing to help out with these issues.
src/OAuth2/Response/AuthenticationError.php:11
Superfluous "WWW-Authenticate".
Resulting header is: "WWW-Authenticate: WWW-Authenticate: bearer realm=Service"
The library currently assumes a small number of scopes, usually passed up front.
The Drupal integration stores scopes separately and has a requirement for supporting an unbounded (unlimited) number of scopes.
This makes getSupportedScopes() unsupportable.
The way I've accomplished this is by returning "*" from getSupportedScopes(), and then checking for that in checkScope() and doing a db query when needed.
See http://drupalcode.org/sandbox/bojanz/1928198.git/blob/refs/heads/7.x-2.x:/lib/Scope.php
However, that is a bit hacky, anyone calling getSupportedScopes() would be surprised by the results.
So, I was wondering if the library could support the unbounded use case better, by optimizing for it. (Since I'm unsure, no pull request yet).
Basically, it would mean removing the getSupportedScopes() method completely, and adding an additional checkScopes-like method (scopeExists() perhaps?) that would check the passed scope against the storage.
What do you think?
One thing of the demo is strange, when I have the code after authorized like http://brentertainment.com/oauth2/demo/authorized?code=fd8af4c12bd9ef42a4baeb03620088e7f3842787
Anyone can use this link and access my data (for 30 Seconds).
Is the problem in oauth or in the code?
When validating if redirect_uri provided on input and clientData. The method validateRedirectUri() cannot be call to...
(OAuth2/Controller/AuthorizeController.php line 97)
I noticed that when we use the same client_id
and client_secret
to request a token on behalf of a user (say, [email protected]), a new token is generated even though a token already exists. In addition, the old token is not deleted.
I have been going through the spec, but could not find anything regarding this.
Is this the correct behaviour?
Cheers :)
Warning: curl_setopt_array(): CURLOPT_FOLLOWLOCATION cannot be activated when an open_basedir
emulation CURLOPT_FOLLOWLOCATION on php alternative curl_exec
function curl_redir_exec($ch)
{
static $curl_loops = 0;
static $curl_max_loops = 20;
if ($curl_loops >= $curl_max_loops)
{
$curl_loops = 0;
return FALSE;
}
curl_setopt($ch, CURLOPT_HEADER, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$data = curl_exec($ch);
list($header, $data) = explode("\r\n\r\n", $data, 2);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if ($http_code == 301 || $http_code == 302)
{
$matches = array();
preg_match('/Location:(.*?)\n/', $header, $matches);
$url = @parse_url(trim(array_pop($matches)));
if (!$url)
{
//couldn't process the url to redirect to
$curl_loops = 0;
return $data;
}
$last_url = parse_url(curl_getinfo($ch, CURLINFO_EFFECTIVE_URL));
if (!$url['scheme'])
$url['scheme'] = $last_url['scheme'];
if (!$url['host'])
$url['host'] = $last_url['host'];
if (!$url['path'])
$url['path'] = $last_url['path'];
$new_url = $url['scheme'] . '://' . $url['host'] . $url['path'] . ($url['query']?'?'.$url['query']:'');
curl_setopt($ch, CURLOPT_URL, $new_url);
//debug('Redirecting to', $new_url);
return curl_redir_exec($ch);
} else {
$curl_loops=0;
return $data;
}
}
Doesn't get any clearer than this: http://tools.ietf.org/html/draft-ietf-oauth-v2-31#section-3.2
The client MUST use the HTTP "POST" method when making access token
requests.
Currently, the library accepts both GET and POST
Hi,
I'm loving this git! I have one thing which I'd really like to do with OAuth2 but I haven't found an option yet. Is it possible to have the OAuth2 client authorize changes to the information on the server?
For example, imagine Lock'dIn has profile information ie {"name":["Robert"]}. Is it possible to change the name saved in Lockd'In through DemoApp (So authorize a change to credentials ie 'DemoApp is requesting to set your Name to Bob')?
Thank you!
I received this question and thought it deserved a public answer:
Can the provider component from your oauth2-server-demo be used for two-legged, non-interactive authentication?
We need to utilize two-legged auth for a fairly traditional client-server model between our various sites and the central authentication server.
Hi guys,
I've noticed every time a user uses the authorization grant, a new authorization code is generated and thus a new access token is returned, regardless if that user already had a valid access token.
On Facebook, if you have authorized the app and have a valid token, that token is returned to you after the usual transparent redirects...
How would you go about implementing something like that?
Thanks
Cédric
On vendor\bshaffer\oauth2-server-php\src\OAuth2\Request.php on line 106
when request method is 'PUT' or 'DELETE'
I have identified the following issues where the project does not adhere to psr-2 standards.
! The class OAuth2_GrantType_AuthorizationCodeInterface in /www/oauth2-server-php/src/OAuth2/ResponseType/AuthorizationCodeInterface.php does not match the file path according to PSR-0 rules
And this is a list of files that also require fixing:
1) src/OAuth2/Autoloader.php
2) src/OAuth2/Controller/AccessController.php
3) src/OAuth2/Controller/AccessControllerInterface.php
4) src/OAuth2/Controller/AuthorizeController.php
5) src/OAuth2/Controller/AuthorizeControllerInterface.php
6) src/OAuth2/Controller/GrantControllerInterface.php
7) src/OAuth2/GrantType/ClientCredentials.php
8) src/OAuth2/GrantType/RefreshToken.php
9) src/OAuth2/GrantTypeInterface.php
10) src/OAuth2/Request.php
11) src/OAuth2/RequestInterface.php
12) src/OAuth2/Response/AuthenticationError.php
13) src/OAuth2/Response/Error.php
14) src/OAuth2/Response/ProviderInterface.php
15) src/OAuth2/Response/Redirect.php
16) src/OAuth2/Response.php
17) src/OAuth2/ResponseType/AccessToken.php
18) src/OAuth2/ResponseType/AccessTokenInterface.php
19) src/OAuth2/ResponseType/AuthorizationCode.php
20) src/OAuth2/ResponseType/AuthorizationCodeInterface.php
21) src/OAuth2/ResponseTypeInterface.php
22) src/OAuth2/Server.php
23) src/OAuth2/Storage/AccessTokenInterface.php
24) src/OAuth2/Storage/AuthorizationCodeInterface.php
25) src/OAuth2/Storage/ClientCredentialsInterface.php
26) src/OAuth2/Storage/ClientInterface.php
27) src/OAuth2/Storage/RefreshTokenInterface.php
28) src/OAuth2/Storage/UserCredentialsInterface.php
29) src/OAuth2/TokenType/Bearer.php
30) src/OAuth2/TokenType/MAC.php
31) src/OAuth2/TokenTypeInterface.php
32) src/OAuth2/Util.php
33) test/bootstrap.php
34) test/lib/OAuth2/Request/TestRequest.php
35) test/lib/OAuth2/Storage/Bootstrap.php
36) test/OAuth2/AutoloadTest.php
37) test/OAuth2/GrantType/AuthorizationCodeTest.php
38) test/OAuth2/GrantType/ClientCredentialsTest.php
39) test/OAuth2/GrantType/RefreshTokenTest.php
40) test/OAuth2/GrantType/UserCredentialsTest.php
41) test/OAuth2/RequestTest.php
42) test/OAuth2/ResponseTest.php
43) test/OAuth2/Server/Access/BasicValidationTest.php
44) test/OAuth2/Server/Authorize/BasicValidationTest.php
45) test/OAuth2/Server/Authorize/CodeTest.php
46) test/OAuth2/Server/Authorize/ImplicitTest.php
47) test/OAuth2/Server/Grant/BasicValidationTest.php
48) test/OAuth2/Storage/PdoTest.php
This is a big enhancement, but needs to be done, as MAC tokens are the most secure way to implement an OAuth2 Server, and do not rely fully on SSL for their protection.
Go through and check all major points to make sure they are compatible with the latest version of the draft
DateTimes are currently passed back in unix timestamp format. We should be able to handle multiple datetime formats, or at least the DateTime
php class.
In addition, we should consider adding typehinting to the storage interfaces, i.e. DateTime $expires
. This will remove ambiguity
We shouldn't issue refresh tokens if there's no refresh_token grant type on the server.
Unsure how to fix this, since individual grant types have no knowledge about other grant types that exist on the server. Perhaps we want to add a $includeRefreshToken parameter to the grant type constructor?
This is a picky change, but the spec names the controllers Resource
, Token
, and Authorize
, while we have named them Access
, Grant
, and Authorize
.
Let's name them to match the spec!
There's to my knowledge no public way to get the $token_param and $scope required, without hardcoding and assume we're using a bearer token.
AccessController could do the same logic as verifyAccessToken for getAccessTokenData as it has access to the protected $tokenType.
Unless I am really missing something...
Create a class to represent client assertion via HttpBasic. This is the default, and should be populated as the default. However, it is not always the case, and can be extended via the spec (see jwt tokens)
Document JWT bearer tokens in GrantType class and in README
After adding the JWT Authorization Grant, we now have a folder called Utils: /OAuth2/Utils
. There also remains a Util.php
: /OAuth2/Util.php
How do you feel about refactoring Util.php
and moving it under /Utils
? We could also rename the class to something that's more descriptive as well.
At the token endpoint, using the client credentials grant flow, I'm calling the OAuth2_Server function getClientCredentials()
, that defers to the GrantController and in turn calls getClientCredentials()
on the grant controller. Problem is that the grant controller doesn't implement getClientCredentials()
. It seems the logic to extract the credentials is in OAuth2_ClientAssertionType_HttpBasic
, and I can just instantiate that class and get the credentials that way - but that doesn't seem like best practice. Any advice?
Not sure why this would work? Why wouldn't you use the client_storages
instead? Now the order of the array is forced since reset()
returns the first element?
Line 35 et 36
'user_credentials' => 'OAuth2_Storage_UserCredentialsInterface',
'user_credentials' => 'OAuth2_Storage_UserCredentialsInterface',
For client authentication, OAuth2_ClientAssertionType_HttpBasic looks for client_secret in POST data if Basic authentication wasn't used. This is allowed by the spec, but it is optional for authorization servers to support.
http://tools.ietf.org/html/rfc6749#section-2.3.1
Alternatively, the authorization server MAY support including the
client credentials in the request-body[...]
Including the client credentials in the request-body using the two
parameters is NOT RECOMMENDED and SHOULD be limited to clients unable
to directly utilize the HTTP Basic authentication scheme (or other
password-based HTTP authentication schemes).
I would like to disable support for it in my authorization server without extending/overriding OAuth2_ClientAssertionType_HttpBasic or implementing my own OAuth2_ClientAssertionTypeInterface.
Accepting client_secret in POST should be configurable somehow. Even better, it could be added to the client details so it can be accepted optionally per client.
Side note: The reference to http://tools.ietf.org/html/rfc6749#section-2.4.1 in OAuth2_ClientAssertionType_HttpBasic is incorrect; it should be 2.3.1.
When submitting a request for an access_token using either the 'Authorization Code' or 'Resource Owner Password Credential' grant, a refresh_token is provided. An example from the latter:
{"access_token":"df680f467c3a410ef615dad7cc480de547467144","expires_in":3600,"token_type":"bearer","scope":null,"refresh_token":"9a74026f2be71d8e81f13d5d607217d93c1ff52d"}
When using the refresh_token from above to request a new access_token, a new refresh_token is not provided, i.e.,
{"access_token":"4a3812a0638e9d4120ba3721e1a9158e72eacacb","expires_in":3600,"token_type":"bearer","scope":null}
While the spec does not strictly require a refresh_token be granted in this case, is it possible to do this?
Thanks much!
OAuth2 is insecure by default.
This library does a good job of closing off many attack vectors.
I did notice two things that could be better by default.
Taken from: http://homakov.blogspot.com/2012/08/saferweb-oauth2a-or-lets-just-fix-it.html
Suggestions:
The article also suggest making allow_implicit a per-client setting. I don't need this on my side because I have the notion of different "contexts" on Drupal side, so all similar clients are grouped, but it might make sense for the library itself.
In any case, the two suggestions above would be easy wins for better security (I like the phrase "if it's insecure by default, then it's insecure")
I receive the following error when trying to call the "User Credentials" grant type (i.e., "Resource Owner Password Credentials Grant" per the OAuth spec at http://tools.ietf.org/html/rfc6749#section-4.3):
PHP Catchable fatal error: Argument 1 passed to OAuth2_GrantType_UserCredentials::validateTokenData() must be an array, boolean given, called in /home/oauth/www/lib/oauth2-server-php-develop/src/OAuth2/Controller/GrantController.php on line 133 and defined in /home/oauth/www/lib/oauth2-server-php-develop/src/OAuth2/GrantType/UserCredentials.php on line 41
Doing some investigation I found that getTokenDataFromRequest() in UserCredentials.php is returning $tokenData as a boolean, but validateTokenData() expects an array.
In order to get it working, I made the following change to getTokenDataFromRequest() in UserCredentials.php:
Replace:
return $tokenData;
With:
// the only piece to pull is the "scope" parameter
$scope = $request->headers('REQUEST_METHOD') == 'POST' ? $request->request('scope') : $request->query('scope');
return array(
"scope" => $scope
);
This behavior follows that in the "Client Credentials" grant type, which I was able to get working out of the box. I'm not sure this is the ideal solution, but it's working.
BTW, I tested all this on the latest development branch.
We wanted to include logging with Monolog and add Symfony's HttpKernel as a dependency in composer.json for the project to set the NullLogger instance if none is given. The constructors would change to
public function __construct($storage = array(), array $config = array(), array $grantTypes = array(), array $responseTypes = array(), OAuth2_ResponseType_AccessTokenInterface $accessTokenResponseType = null, \Symfony\Component\HttpKernel\Log\LoggerInterface $logger = null)
{
...
//set the logger
$this->logger = $logger;
if (!$this->logger instanceof \Symfony\Component\HttpKernel\Log\LoggerInterface) {
$this->logger = new \Symfony\Component\HttpKernel\Log\NullLogger();
}
}
You can then add you own implementation or Monolog and get logs from the server like this:
use Monolog\Logger;
use Monolog\Handler\StreamHandler;
// create a log channel
$logger = new Logger('name');
$logger->pushHandler(new StreamHandler('path/to/your.log', Logger::DEBUG));
$server = new EasyBib\OAuth2\Server($app['oauth_storage'], $config, array(), array(), null, $logger);
An example can be found here: dazz/oauth2-server-php/feature/addLogging. This branch is now outdated so I would make a new branch from the develop branch to add it.
Before I add all my code again, I wanted to know if adding a dependency to HttpKernels NullLogger is ok an what do you think about this approach?
Having a logfile definitely helped us implement the client for testing the server.
Unable to retrieve access_token using getAccessTokenParameter
from Bearer.php
. For example, an HTTP POST with Header:
Authorization: Bearer 713eca9cb36f9c1be6b86d5dc242b5bb00c88598
is sent and a request is created:
$request = OAuth2_Request::createFromGlobals();
Doing a var_dump of $request:
...
[server] => Array
(
[REDIRECT_HTTP_AUTHORIZATION] => Bearer 713eca9cb36f9c1be6b86d5dc242b5bb00c88598
[REDIRECT_STATUS] => 200
[HTTP_AUTHORIZATION] => Bearer 713eca9cb36f9c1be6b86d5dc242b5bb00c88598
[HTTP_HOST] => 192.168.2.13
[HTTP_USER_AGENT] => Mozilla/5.0 (Windows NT 6.2; WOW64; rv:17.0) Gecko/20100101 Firefox/17.0
[HTTP_ACCEPT] => text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
[HTTP_ACCEPT_LANGUAGE] => en-US,en;q=0.5
[HTTP_ACCEPT_ENCODING] => gzip, deflate
[HTTP_DNT] => 1
[HTTP_CONNECTION] => keep-alive
[CONTENT_TYPE] => application/x-www-form-urlencoded; charset=UTF-8
[CONTENT_LENGTH] => 61
[HTTP_COOKIE] => PHPSESSID=cofdhm7vqquplkbvjjf9ofutp2
[HTTP_PRAGMA] => no-cache
[HTTP_CACHE_CONTROL] => no-cache
[PATH] => /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
[SERVER_SIGNATURE] => <address>Apache/2.2.22 (Ubuntu) Server at 192.168.2.13 Port 80</address>
[SERVER_SOFTWARE] => Apache/2.2.22 (Ubuntu)
[SERVER_NAME] => 192.168.2.13
[SERVER_ADDR] => 192.168.2.13
[SERVER_PORT] => 80
[REMOTE_ADDR] => 192.168.2.12
[DOCUMENT_ROOT] => /var/www
[SERVER_ADMIN] => webmaster@localhost
[SCRIPT_FILENAME] => /var/www/index.php
[REMOTE_PORT] => 56430
[REDIRECT_URL] => /admin/addclient
[GATEWAY_INTERFACE] => CGI/1.1
[SERVER_PROTOCOL] => HTTP/1.1
[REQUEST_METHOD] => POST
[QUERY_STRING] =>
[REQUEST_URI] => /admin/addclient
[SCRIPT_NAME] => /index.php
[PHP_SELF] => /index.php
[REQUEST_TIME] => 1356741875
)
...
[headers] => Array
(
[AUTHORIZATION] => Bearer 713eca9cb36f9c1be6b86d5dc242b5bb00c88598
[HOST] => 192.168.2.13
[USER_AGENT] => Mozilla/5.0 (Windows NT 6.2; WOW64; rv:17.0) Gecko/20100101 Firefox/17.0
[ACCEPT] => text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
[ACCEPT_LANGUAGE] => en-US,en;q=0.5
[ACCEPT_ENCODING] => gzip, deflate
[DNT] => 1
[CONNECTION] => keep-alive
[CONTENT_TYPE] => application/x-www-form-urlencoded; charset=UTF-8
[CONTENT_LENGTH] => 61
[COOKIE] => PHPSESSID=cofdhm7vqquplkbvjjf9ofutp2
[PRAGMA] => no-cache
[CACHE_CONTROL] => no-cache
)
...
I can get it working by changing $request
to look for the AUTHORIZATION
in ->$headers
from ->server
, i.e.,
public function getAccessTokenParameter(OAuth2_RequestInterface $request)
{
$headers = $request->headers('AUTHORIZATION');
By working, I mean the following returns a value for $access_token
:
$bearer = new OAuth2_TokenType_Bearer();
$access_token = $bearer->getAccessTokenParameter($request);
My question-- am I implementing this incorrectly? Please note the following RewriteRule was added to .htaccess to allow for PHP parsing of Authorization other than Basic or Digest:
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
I have been using the new ScopeInterface
and the Storage_ScopeInterface
and love the flexibility it offers.
I think it can be slightly enhanced to allow more flexibility.
In an application I am building, 2 grant types are allowed: JWT Authorization Grant and Authorization Code. The JWT type is used for service accounts, so should have access to a set of scopes that are used for administrating the system. Authorization Code grants would not have access to these scopes.
Similarly, it is also possible to have a system where different client_ids
have access to a different set of scopes.
I think it will be beneficial if we can extend the ScopeInterface
to include a validateScope($client_id, $user_id, array $scope = null)
.
This would be called by createAccessToken()
in the AccessToken
response type. Essentially, the scope, client_id and user_id is passed to validateScope
.
validateScope
then looks up the scopes that are available for the client_id
and user_id
and perhaps the grant type (not sure how this should be done yet). Perhaps instead of passing the client_id
and user_id
, we can pass in the $request
, so the method gets access to all information about the request.
validateScope
would then validate the scopes and return an array containing only the valid scopes (invalid or not allowed scopes are removed). This can then be sent back to the client:
$token = array(
"access_token" => $this->generateAccessToken(),
"expires_in" => $this->config['access_lifetime'],
"token_type" => $this->config['token_type'],
"scope" => $this->scopeUtil->validateScope($request)
);
Let me know what you think :)
So the "FromRequest' part is mostly untrue, the method could use a better name.
When using the client_credentials grant type, scope is not validated.
$tokenData['scope'] is fetched from the request by getTokenDataFromRequest().
$scope is also fetched from request by:
$scope = $this->scopeUtil->getScopeFromRequest($request);
So the scope check compares two same values:
if (!is_null($scope) && !$this->scopeUtil->checkScope($scope, $tokenData["scope"])) {
and doesn't actually validate anything, an invalid scope is set on the issued access token.
When using the password grant type, the requested scope is never set (the default scope is set instead).
Since the user credentials returned from getTokenDataFromRequest() contain no scope, the default scope is assigned every time.
Maybe the scope check needs to move somewhere else? $grantType->validateTokenData() perhaps?
Currently, storages implement getAccessToken()
and setAccessToken()
to get and save access tokens.
In createAccessToken
in OAuth2_ResponseType_AccessToken.php
:
The authorization server MAY fully or partially ignore the scope
requested by the client based on the authorization server policy or
the resource owner's instructions. If the issued access token scope
is different from the one requested by the client, the authorization
server MUST include the "scope" response parameter to inform the
client of the actual scope granted.
If the client omits the scope parameter when requesting
authorization, the authorization server MUST either process the
request using a pre-defined default value, or fail the request
indicating an invalid scope. The authorization server SHOULD
document its scope requirements and default value (if defined).
I propose that we add the following enhancements to createAccessToken()
:
setAccessToken()
of the storage driver and return a list of scopes that is assigned to the token if successfully. If write to storage was unsuccessful, return a false.Let me know what you think :)
Is ist possible to change scope of properties $db and $config in "OAuth2_Storage_Pdo" from "private" to "protected" so that people can extend the class and implement their own "getUser" function. For example for this usecase: #68
The library uses OAuth 2 draft URIs for the error_uri. The RFC has been published and it'd be better to reference the RFC URI instead.
http://tools.ietf.org/html/draft-ietf-oauth-v2-31#section-3.2
http://tools.ietf.org/html/rfc6749#section-3.2
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.