mirror of
https://github.com/elyby/oauth2-server.git
synced 2024-12-27 23:40:22 +05:30
Updated docs
This commit is contained in:
parent
164f777e38
commit
dc98afdda0
@ -1,2 +1,18 @@
|
||||
Getting Started:
|
||||
Introduction: '/'
|
||||
Introduction: '/'
|
||||
Terminology: '/terminology/'
|
||||
Installation: '/installation/'
|
||||
Implementing storage interfaces: '/implementing-storage-interfaces/'
|
||||
Authorization Server:
|
||||
'Which grant?': '/authorization-server/which-grant/'
|
||||
'Authorization Code Grant': '/authorization-server/auth-code-grant/'
|
||||
'Client Credentials Grant': '/authorization-server/client-credentials-grant/'
|
||||
'Password Grant': '/authorization-server/resource-owner-password-credentials-grant/'
|
||||
'Refresh Token Grant': '/authorization-server/refresh-token-grant/'
|
||||
'Server Customisation': '/authorization-server/customisation/'
|
||||
'Events': '/authorization-server/events/'
|
||||
'Custom token identifier generator': '/authorization-server/custom-token-identifier-generator/'
|
||||
'Custom token types': '/authorization-server/custom-token-types/'
|
||||
'Custom grants': '/authorization-server/custom-grants/'
|
||||
Resource Server:
|
||||
'Securing your API': '/resource-server/securing-your-api/'
|
@ -1,4 +1,4 @@
|
||||
title:
|
||||
tagline:
|
||||
description:
|
||||
google_analytics_tracking_id:
|
||||
title: OAuth 2.0 Server
|
||||
tagline: PHP, meet OAuth
|
||||
description: A standards compliant OAuth 2.0 server
|
||||
google_analytics_tracking_id: UA-46050814-5
|
194
auth-server-auth-code.md
Executable file
194
auth-server-auth-code.md
Executable file
@ -0,0 +1,194 @@
|
||||
---
|
||||
layout: default
|
||||
title: Authorization server with authorization code grant
|
||||
permalink: /authorization-server/auth-code-grant/
|
||||
---
|
||||
|
||||
# Authorization server with authorization code grant
|
||||
|
||||
## Setup
|
||||
|
||||
Wherever you intialise your objects, initialize a new instance of the authorization server and bind the storage interfaces and authorization code grant:
|
||||
|
||||
~~~ php
|
||||
$server = new \League\OAuth2\Server\AuthorizationServer;
|
||||
|
||||
$server->setSessionStorage(new Storage\SessionStorage);
|
||||
$server->setAccessTokenStorage(new Storage\AccessTokenStorage);
|
||||
$server->setClientStorage(new Storage\ClientStorage);
|
||||
$server->setScopeStorage(new Storage\ScopeStorage);
|
||||
$server->setAuthCodeStorage(new Storage\AuthCodeStorage);
|
||||
|
||||
$authCodeGrant = new \League\OAuth2\Server\Grant\AuthCodeGrant();
|
||||
$server->addGrantType($authCodeGrant);
|
||||
~~~
|
||||
|
||||
|
||||
## Implementation
|
||||
|
||||
Create a route which will respond to a request to `/oauth` which is where the client will redirect the user to.
|
||||
|
||||
~~~ php
|
||||
$router->get('/oauth', function (Request $request) use ($server) {
|
||||
|
||||
// First ensure the parameters in the query string are correct
|
||||
try {
|
||||
|
||||
$authParams = $server->getGrantType('authorization_code')->checkAuthorizeParams();
|
||||
|
||||
} catch (\Exception $e) {
|
||||
|
||||
return new Response(
|
||||
json_encode([
|
||||
'error' => $e->errorType,
|
||||
'message' => $e->getMessage()
|
||||
]),
|
||||
$e->httpStatusCode, // All of the library's exception classes have a status code specific to the error
|
||||
$e->getHttpHeaders() // Some exceptions have headers which need to be sent
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
// Everything is okay, save $authParams to the a session and redirect the user to sign-in
|
||||
|
||||
$response = new Response('', 302, [
|
||||
'Location' => '/signin'
|
||||
]);
|
||||
|
||||
return $response;
|
||||
|
||||
});
|
||||
~~~
|
||||
|
||||
|
||||
|
||||
The user is redirected to a sign-in screen. If the user is not signed in then sign them in.
|
||||
|
||||
~~~ php
|
||||
$router->get('/signin', function (Request $request) use ($server) {
|
||||
|
||||
if ($user) {
|
||||
|
||||
$response = new Response('', 302, [
|
||||
'Location' => '/authorize'
|
||||
]);
|
||||
|
||||
return $response;
|
||||
|
||||
} else {
|
||||
|
||||
// Logic here to show the a sign-in form and sign the user in
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
~~~
|
||||
|
||||
|
||||
The final part is to show a web page that tells the user the name of the client, the scopes requested and two buttons, an "Approve" button and a "Deny" button.
|
||||
|
||||
View:
|
||||
|
||||
~~~ php
|
||||
// Authorize view
|
||||
<h1><?= $authParams['client']->getName() ?> would like to access:</h1>
|
||||
|
||||
<ul>
|
||||
<?php foreach ($authParams['scopes'] as $scope): ?>
|
||||
<li>
|
||||
<?= $scope->getName() ?>: <?= $scope->getDescription() ?>
|
||||
</li>
|
||||
<?= endforeach; ?>
|
||||
</ul>
|
||||
|
||||
<form method="post">
|
||||
<input type="submit" value="Approve" name="authorization">
|
||||
<input type="submit" value="Deny" name="authorization">
|
||||
</form>
|
||||
~~~
|
||||
|
||||
|
||||
|
||||
|
||||
Route:
|
||||
|
||||
~~~ php
|
||||
$router->get('/signin', function (Request $request) use ($server) {
|
||||
|
||||
if (!isset($_POST['authorization'])) {
|
||||
// show form
|
||||
}
|
||||
|
||||
// If the user authorizes the request then redirect the user back with an authorization code
|
||||
|
||||
if ($_POST['authorization'] === 'Approve') {
|
||||
$redirectUri = $server->getGrantType('authorization_code')->newAuthorizeRequest('user', 1, $authParams);
|
||||
|
||||
$response = new Response('', 302, [
|
||||
'Location' => $redirectUri
|
||||
]);
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
// The user denied the request so redirect back with a message
|
||||
else {
|
||||
|
||||
$error = new \League\OAuth2\Server\Util\AccessDeniedException;
|
||||
|
||||
$redirectUri = new \League\OAuth2\Server\Util\RedirectUri(
|
||||
$authParams['redirect_uri'],
|
||||
[
|
||||
'error' => $error->errorType,
|
||||
'message' => $e->getMessage()
|
||||
]
|
||||
);
|
||||
|
||||
$response = new Response('', 302, [
|
||||
'Location' => $redirectUri
|
||||
]);
|
||||
|
||||
return $response;
|
||||
}
|
||||
});
|
||||
~~~
|
||||
|
||||
The user will be redirected back to the client with either an error message or an authorization code.
|
||||
|
||||
If the client recieves an authorization code it will request to turn it into an access token. For this you need an `/access_token` endpoint.
|
||||
|
||||
~~~ php
|
||||
$router->post('/access_token', function (Request $request) use ($server) {
|
||||
|
||||
try {
|
||||
|
||||
$response = $server->issueAccessToken();
|
||||
return new Response(
|
||||
json_encode($response),
|
||||
200
|
||||
[
|
||||
'Content-type' => 'application/json',
|
||||
'Cache-Control' => 'no-store',
|
||||
'Pragma' => 'no-store'
|
||||
]
|
||||
);
|
||||
|
||||
} catch (\Exception $e) {
|
||||
|
||||
return new Response(
|
||||
json_encode([
|
||||
'error' => $e->errorType,
|
||||
'message' => $e->getMessage()
|
||||
]),
|
||||
$e->httpStatusCode,
|
||||
$e->getHttpHeaders()
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
~~~
|
||||
|
||||
### Notes
|
||||
|
||||
* You could combine the sign-in form and authorize form into one form
|
59
auth-server-client-credentials.md
Executable file
59
auth-server-client-credentials.md
Executable file
@ -0,0 +1,59 @@
|
||||
---
|
||||
layout: default
|
||||
title: Authorization server with client credentials grant
|
||||
permalink: /authorization-server/client-credentials-grant/
|
||||
---
|
||||
|
||||
# Authorization server with client credentials grant
|
||||
|
||||
## Setup
|
||||
|
||||
Wherever you intialise your objects, initialize a new instance of the authorization server and bind the storage interfaces and authorization code grant:
|
||||
|
||||
~~~ php
|
||||
$server = new \League\OAuth2\Server\AuthorizationServer;
|
||||
|
||||
$server->setSessionStorage(new Storage\SessionStorage);
|
||||
$server->setAccessTokenStorage(new Storage\AccessTokenStorage);
|
||||
$server->setClientStorage(new Storage\ClientStorage);
|
||||
$server->setScopeStorage(new Storage\ScopeStorage);
|
||||
|
||||
$clientCredentials = new \League\OAuth2\Server\Grant\ClientCredentialsGrant();
|
||||
$server->addGrantType($clientCredentials);
|
||||
~~~
|
||||
|
||||
## Implementation
|
||||
|
||||
The client will request an access token so create an `/access_token` endpoint.
|
||||
|
||||
~~~ php
|
||||
$router->post('/access_token', function (Request $request) use ($server) {
|
||||
|
||||
try {
|
||||
|
||||
$response = $server->issueAccessToken();
|
||||
return new Response(
|
||||
json_encode($response),
|
||||
200
|
||||
[
|
||||
'Content-type' => 'application/json',
|
||||
'Cache-Control' => 'no-store',
|
||||
'Pragma' => 'no-store'
|
||||
]
|
||||
);
|
||||
|
||||
} catch (\Exception $e) {
|
||||
|
||||
return new Response(
|
||||
json_encode([
|
||||
'error' => $e->errorType,
|
||||
'message' => $e->getMessage()
|
||||
]),
|
||||
$e->httpStatusCode,
|
||||
$e->getHttpHeaders()
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
~~~
|
9
auth-server-custom-grants.md
Executable file
9
auth-server-custom-grants.md
Executable file
@ -0,0 +1,9 @@
|
||||
---
|
||||
layout: default
|
||||
title: Authorization server custom grants
|
||||
permalink: /authorization-server/custom-grants/
|
||||
---
|
||||
|
||||
# Authorization server custom grants
|
||||
|
||||
## TODO
|
9
auth-server-custom-token-identifier-generator.md
Executable file
9
auth-server-custom-token-identifier-generator.md
Executable file
@ -0,0 +1,9 @@
|
||||
---
|
||||
layout: default
|
||||
title: Authorization server custom token identifier generator
|
||||
permalink: /authorization-server/custom-token-identifier-generator/
|
||||
---
|
||||
|
||||
# Authorization server custom token identifier generator
|
||||
|
||||
## TODO
|
9
auth-server-custom-token-types.md
Executable file
9
auth-server-custom-token-types.md
Executable file
@ -0,0 +1,9 @@
|
||||
---
|
||||
layout: default
|
||||
title: Authorization server custom token types
|
||||
permalink: /authorization-server/custom-token-types/
|
||||
---
|
||||
|
||||
# Authorization server custom token types
|
||||
|
||||
## TODO
|
9
auth-server-customisation.md
Executable file
9
auth-server-customisation.md
Executable file
@ -0,0 +1,9 @@
|
||||
---
|
||||
layout: default
|
||||
title: Authorization server customisation
|
||||
permalink: /authorization-server/customisation/
|
||||
---
|
||||
|
||||
# Authorization server customisation
|
||||
|
||||
## TODO
|
9
auth-server-events.md
Executable file
9
auth-server-events.md
Executable file
@ -0,0 +1,9 @@
|
||||
---
|
||||
layout: default
|
||||
title: Authorization server events
|
||||
permalink: /authorization-server/events/
|
||||
---
|
||||
|
||||
# Authorization server events
|
||||
|
||||
## TODO
|
62
auth-server-password.md
Executable file
62
auth-server-password.md
Executable file
@ -0,0 +1,62 @@
|
||||
---
|
||||
layout: default
|
||||
title: Authorization server with resource owner password credentials grant
|
||||
permalink: /authorization-server/resource-owner-password-credentials-grant/
|
||||
---
|
||||
|
||||
# Authorization server with resource owner password credentials grant
|
||||
|
||||
## Setup
|
||||
|
||||
Wherever you intialise your objects, initialize a new instance of the authorization server and bind the storage interfaces and authorization code grant:
|
||||
|
||||
~~~ php
|
||||
$server = new \League\OAuth2\Server\AuthorizationServer;
|
||||
|
||||
$server->setSessionStorage(new Storage\SessionStorage);
|
||||
$server->setAccessTokenStorage(new Storage\AccessTokenStorage);
|
||||
$server->setClientStorage(new Storage\ClientStorage);
|
||||
$server->setScopeStorage(new Storage\ScopeStorage);
|
||||
|
||||
$passwordGrant = new \League\OAuth2\Server\Grant\PasswordGrant();
|
||||
$passwordGrant->setVerifyCredentialsCallback(function ($username, $password) {
|
||||
// implement logic here to validate a username and password, return an ID if valid, otherwise return false
|
||||
});
|
||||
~~~
|
||||
|
||||
|
||||
## Implementation
|
||||
|
||||
The client will request an access token so create an `/access_token` endpoint.
|
||||
|
||||
~~~ php
|
||||
$router->post('/access_token', function (Request $request) use ($server) {
|
||||
|
||||
try {
|
||||
|
||||
$response = $server->issueAccessToken();
|
||||
return new Response(
|
||||
json_encode($response),
|
||||
200
|
||||
[
|
||||
'Content-type' => 'application/json',
|
||||
'Cache-Control' => 'no-store',
|
||||
'Pragma' => 'no-store'
|
||||
]
|
||||
);
|
||||
|
||||
} catch (\Exception $e) {
|
||||
|
||||
return new Response(
|
||||
json_encode([
|
||||
'error' => $e->errorType,
|
||||
'message' => $e->getMessage()
|
||||
]),
|
||||
$e->httpStatusCode,
|
||||
$e->getHttpHeaders()
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
~~~
|
26
auth-server-refresh-token.md
Executable file
26
auth-server-refresh-token.md
Executable file
@ -0,0 +1,26 @@
|
||||
---
|
||||
layout: default
|
||||
title: Authorization server with refresh token grant
|
||||
permalink: /authorization-server/refresh-token-grant/
|
||||
---
|
||||
|
||||
# Authorization server with refresh token grant
|
||||
|
||||
## Setup
|
||||
|
||||
Wherever you intialise your objects, initialize a new instance of the authorization server and bind the storage interfaces and authorization code grant:
|
||||
|
||||
~~~ php
|
||||
$server = new \League\OAuth2\Server\AuthorizationServer;
|
||||
|
||||
$server->setSessionStorage(new Storage\SessionStorage);
|
||||
$server->setAccessTokenStorage(new Storage\AccessTokenStorage);
|
||||
$server->setClientStorage(new Storage\ClientStorage);
|
||||
$server->setScopeStorage(new Storage\ScopeStorage);
|
||||
$server->setAccessTokenStorage(new Storage\RefreshTokenStorage);
|
||||
|
||||
$refrehTokenGrant = new \League\OAuth2\Server\Grant\RefreshTokenGrant();
|
||||
$server->addGrantType($refrehTokenGrant);
|
||||
~~~
|
||||
|
||||
When the refresh token grant is enabled, a refresh token will automatically be created with access tokens issued requested using the [authorization code](/authorization-server/auth-code-grant/) or [resource owner password credentials](/authorization-server/resource-owner-password-credentials-grant/) grants.
|
115
auth-server-which-grant.md
Executable file
115
auth-server-which-grant.md
Executable file
@ -0,0 +1,115 @@
|
||||
---
|
||||
layout: default
|
||||
title: Which OAuth 2.0 grant should I use?
|
||||
permalink: /authorization-server/which-grant/
|
||||
---
|
||||
|
||||
# Which OAuth 2.0 grant should I use?
|
||||
|
||||
This page was originally posted at [http://alexbilbie.com/2013/02/a-guide-to-oauth-2-grants/](http://alexbilbie.com/2013/02/a-guide-to-oauth-2-grants/).
|
||||
|
||||
---
|
||||
|
||||
OAuth 2.0 by it’s nature is a very flexible standard and can be adapted to work in many different scenarios. The [core specification](http://tools.ietf.org/html/rfc6749) describes four authorisation grants:
|
||||
|
||||
* Authorisation code grant
|
||||
* Implicit grant
|
||||
* Resource owner credentials grant
|
||||
* Client credentials grant
|
||||
|
||||
The specification also details another grant called the _refresh token grant_.
|
||||
|
||||
Furthermore there are a number of other grants that have gone through the IETF ratification process (none of which at the time of writing have been formally standardised):
|
||||
|
||||
* Message authentication code (MAC) tokens
|
||||
* SAML 2.0 Bearer Assertion Profiles
|
||||
* JSON web token grant
|
||||
|
||||
The end goal of each of these grants (except the refresh token grant) is for the client application to have an access token (which represents a user’s permission for the client to access their data) which it can use to authenticate a request to an API endpoint.
|
||||
|
||||
This page describes each of the above grants and their appropriate use cases.
|
||||
|
||||
As a refresher here is a quick glossary of OAuth terms (taken from the core spec):
|
||||
|
||||
* **Resource owner (a.k.a. the User)** - An entity capable of granting access to a protected resource. When the resource owner is a person, it is referred to as an end-user.
|
||||
* **Resource server (a.k.a. the API server)** - The server hosting the protected resources, capable of accepting and responding to protected resource requests using access tokens.
|
||||
* **Client** - An application making protected resource requests on behalf of the resource owner and with its authorisation. The term client does not imply any particular implementation characteristics (e.g. whether the application executes on a server, a desktop, or other devices).
|
||||
* **Authorisation server** - The server issuing access tokens to the client after successfully authenticating the resource owner and obtaining authorisation.
|
||||
|
||||
## Authorisation code grant ([section 4.1](http://tools.ietf.org/html/rfc6749#section-4.1))
|
||||
|
||||
**To enable this grant:**
|
||||
|
||||
~~~ php
|
||||
$authCodeGrant = new \League\OAuth2\Server\Grant\AuthCodeGrant();
|
||||
$server->addGrantType($authCodeGrant);
|
||||
~~~
|
||||
|
||||
The authorisation code grant is the grant that most people think of when OAuth is described.
|
||||
|
||||
If you’ve ever signed into a website or application with your Twitter/Facebook/Google/(insert major Internet company here) account then you’ll have experienced using this grant.
|
||||
|
||||
Essentially a user will click on a “sign in with Facebook” (or other <attr title=“Identity Provider”>IdP</attr>) and then be redirected from the application/website (the “client”) to the IdP authorisation server. The user will then sign in to the IdP with their credentials, and then - if they haven’t already - authorise the client to allow it to use the user’s data (such as their name, email address, etc). If they authorise the request the user will be redirected back to the client with a token (called the authorisation code) in the query string (e.g. `http://client.com/redirect?code=XYZ123`) which the client will capture and exchange for an access token in the background.
|
||||
|
||||
This grant is suitable where the resource owner is a user and they are using a client which is allows a user to interact with a website in a browser. An obvious example is the client being another website, but desktop applications such as Spotify or Reeder use embedded browsers.
|
||||
|
||||
Some mobile applications use this flow and again use an embedded browser (or redirect the user to the native browser and then are redirected back to the app using a custom protocol).
|
||||
|
||||
In this grant the access token is kept private from the resource owner.
|
||||
|
||||
If you have a mobile application that is for your own service (such as the official Spotify or Facebook apps on iOS) it isn’t appropriate to use this grant as the app itself should already be trusted by your authorisation server and so the _resource owner credentials grant would be more appropriate.
|
||||
|
||||
## Implicit grant ([section 4.2](http://tools.ietf.org/html/rfc6749#section-4.2))
|
||||
|
||||
The implicit grant is similar to the authentication code grant described above. The user will be redirected in a browser to the IdP authorisation server, sign in, authorise the request but instead of being returned to the client with an authentication code they are redirected with an access token straight away.
|
||||
|
||||
The purpose of the implicit grant is for use by clients which are not capable of keeping the client’s own credentials secret; for example a JavaScript only application.
|
||||
|
||||
**If you decide to implement this grant then you must be aware that the access token should be treated as “public knowledge” (like a public RSA key)** and therefore it must have a very limited permissions when interacting with the API server. For example an access token that was granted using the authentication code grant could have permission to be used to delete resources owned by the user, however an access token granted through the implicit flow should only be able to “read” resources and never perform any destructive operations (i.e. non-idempotent method).
|
||||
|
||||
## Resource owner credentials grant ([section 4.3](http://tools.ietf.org/html/rfc6749#section-4.3))
|
||||
|
||||
**To enable this grant:**
|
||||
|
||||
~~~ php
|
||||
$passwordGrant = new \League\OAuth2\Server\Grant\PasswordGrant();
|
||||
$passwordGrant->setVerifyCredentialsCallback(function ($username, $password) {
|
||||
// implement logic here to validate a username and password,
|
||||
// return an ID if valid, return false otherwise
|
||||
});
|
||||
$server->addGrantType($passwordGrant);
|
||||
~~~
|
||||
|
||||
When this grant is implemented the client itself will ask the user for their username and password (as opposed to being redirected to an IdP authorisation server to authenticate) and then send these to the authorisation server along with the client’s own credentials. If the authentication is successful then the client will be issued with an access token.
|
||||
|
||||
This grant is suitable for trusted clients such as a service’s own mobile client (for example Spotify’s iOS app). You could also use this in software where it’s not easy to implement the authorisation code - for example we bolted this authorisation grant into [OwnCloud](http://owncloud.org/) so we could retrieve details about a user that we couldn’t access over LDAP from the university’s Active Directory server.
|
||||
|
||||
## Client credentials grant ([section 4.4](http://tools.ietf.org/html/rfc6749#section-4.4))
|
||||
|
||||
**To enable this grant:**
|
||||
|
||||
~~~ php
|
||||
$clientCredentials = new League\OAuth2\Server\Grant\ClientCredentialsGrant();
|
||||
server->addGrantType($clientCredentials);
|
||||
~~~
|
||||
|
||||
This grant is similar to the resource owner credentials grant except only the client’s credentials are used to authenticate a request for an access token. Again this grant should only be allowed to be used by trusted clients.
|
||||
|
||||
This grant is suitable for machine-to-machine authentication, for example for use in a cron job which is performing maintenance tasks over an API. Another example would be a client making requests to an API that don’t require user’s permission.
|
||||
|
||||
When someone visits a member of staff’s page on the [University of Lincoln staff directory](http://staff.lincoln.ac.uk/) the website uses it’s own access token (that was generated using this grant) to authenticate a request to the API server to get the data about the member of staff that is used to build the page. When a member of staff signs in to update their profile however their own access token is used to retrieve and update their data. Therefore there is a good separation of concerns and we can easily restrict permissions that each type of access token has.
|
||||
|
||||
## Refresh token grant ([section 1.5](http://tools.ietf.org/html/rfc6749#section-1.5))
|
||||
|
||||
**To enable this grant:**
|
||||
|
||||
~~~ php
|
||||
$refrehTokenGrant = new \League\OAuth2\Server\Grant\RefreshTokenGrant();
|
||||
$server->addGrantType($refrehTokenGrant);
|
||||
~~~
|
||||
|
||||
The OAuth 2.0 specification also details a fifth grant which can be used to “refresh” (i.e. renew) an access token which has expired.
|
||||
|
||||
Authorisation servers which support this grant will also issue a “refresh token” when it returns an access token to a client. When the access token expires instead of sending the user back through the authorisation code grant the client can use to the refresh token to retrieve a new access token with the same permissions as the old one.
|
||||
|
||||
A problem with the grant is that it means the client has to maintain state of each token and then either on a cron job keep access tokens up to date or when it tries to make a request and it fails then go and update the access token and repeat the request.
|
60
implementing-storage-classes.md
Executable file
60
implementing-storage-classes.md
Executable file
@ -0,0 +1,60 @@
|
||||
---
|
||||
layout: default
|
||||
title: Installation
|
||||
permalink: /implementing-storage-interfaces/
|
||||
---
|
||||
|
||||
# Implementing the storage interfaces
|
||||
|
||||
In order to use both the resource server and authorization server you need need to implement a number of interfaces.
|
||||
|
||||
If you are using the resource server you need to implement the following interfaces:
|
||||
|
||||
* `League\OAuth2\Server\Storage\SessionInterface` - contains methods for retrieving and setting sessions
|
||||
* `League\OAuth2\Server\Storage\AccessTokenInterface` - contains methods for retrieving, creating and deleting access tokens
|
||||
* `League\OAuth2\Server\Storage\ClientStorage` - single method to get a client
|
||||
* `League\OAuth2\Server\Storage\ScopeStorage` - single method to get a scope
|
||||
|
||||
If you are using the authorization server you need to implement the following interfaces:
|
||||
|
||||
* `League\OAuth2\Server\Storage\SessionInterface` - contains methods for retrieving and setting sessions
|
||||
* `League\OAuth2\Server\Storage\AccessTokenInterface` - contains methods for retrieving, creating and deleting access tokens
|
||||
* `League\OAuth2\Server\Storage\ClientStorage` - single method to get a client
|
||||
* `League\OAuth2\Server\Storage\ScopeStorage` - single method to get a scope
|
||||
|
||||
If you are using the authorization code grant you also need to implement:
|
||||
|
||||
* `League\OAuth2\Server\Storage\AuthCodeInterface` - contains methods for retrieving, creating and deleting authorization codes
|
||||
|
||||
If you are using the refresh token grant you also need to implement:
|
||||
|
||||
* `League\OAuth2\Server\Storage\RefreshTokenInterface` - contains methods for retrieving, creating and deleting refresh tokens
|
||||
|
||||
Once you have written your class implementations then inject them into the server like so:
|
||||
|
||||
~~~ php
|
||||
// Resource server
|
||||
$sessionStorage = new Storage\SessionStorage();
|
||||
$accessTokenStorage = new Storage\AccessTokenStorage();
|
||||
$clientStorage = new Storage\ClientStorage();
|
||||
$scopeStorage = new Storage\ScopeStorage();
|
||||
|
||||
$server = new ResourceServer(
|
||||
$sessionStorage,
|
||||
$accessTokenStorage,
|
||||
$clientStorage,
|
||||
$scopeStorage
|
||||
);
|
||||
|
||||
// Authorization server
|
||||
$server->setSessionStorage(new Storage\SessionStorage);
|
||||
$server->setAccessTokenStorage(new Storage\AccessTokenStorage);
|
||||
$server->setRefreshTokenStorage(new Storage\RefreshTokenStorage);
|
||||
$server->setClientStorage(new Storage\ClientStorage);
|
||||
$server->setScopeStorage(new Storage\ScopeStorage);
|
||||
$server->setAuthCodeStorage(new Storage\AuthCodeStorage);
|
||||
~~~
|
||||
|
||||
If you are using a relational database you can find some example storage implementations in the `examples/relational` folder in the codebase.
|
||||
|
||||
You don't have to use a database to store all of your settings
|
27
index.md
Normal file → Executable file
27
index.md
Normal file → Executable file
@ -1,8 +1,27 @@
|
||||
---
|
||||
layout: default
|
||||
permalink: /
|
||||
title: Introduction
|
||||
---
|
||||
|
||||
Introduction
|
||||
============
|
||||
# Introduction
|
||||
|
||||
<ul class="quick_links">
|
||||
<li><a class="github" href="https://github.com/thephpleague/oauth2-server">View Source</a></li>
|
||||
<li><a class="twitter" href="https://twitter.com/alexbilbie">Follow Alex Bilbie on Twitter</a></li>
|
||||
</ul>
|
||||
|
||||
This library makes working with OAuth 2.0 trivial. You can easily configure an OAuth 2.0 server to protect your API with access tokens, or allow clients to request new access tokens and refresh them.
|
||||
|
||||
It supports out of the box the following grants:
|
||||
|
||||
* Authorization code grant
|
||||
* Client credentials grant
|
||||
* Resource owner password credentials grant
|
||||
* Refresh grant
|
||||
|
||||
You can also define your own grants.
|
||||
|
||||
In addition it supports the following token types:
|
||||
|
||||
* Bearer tokens
|
||||
* MAC tokens (coming soon)
|
||||
* JSON web tokens (coming soon)
|
25
installation.md
Executable file
25
installation.md
Executable file
@ -0,0 +1,25 @@
|
||||
---
|
||||
layout: default
|
||||
title: Installation
|
||||
permalink: /installation/
|
||||
---
|
||||
|
||||
# Installation
|
||||
|
||||
The recommended way of installing the library is via Composer.
|
||||
|
||||
If you already have a composer.json file in your root then add `"league/oauth2-server": "4.*"` in the require object. Then run `composer update`.
|
||||
|
||||
Otherwise create a new file in your project root called composer.json add set the contents to:
|
||||
|
||||
~~~ javascript
|
||||
{
|
||||
"require": {
|
||||
"league/oauth2-server": "4.0.*@dev"
|
||||
}
|
||||
}
|
||||
~~~
|
||||
|
||||
Now, assuming you have [installed Composer](https://getcomposer.org/download/) run `composer update`.
|
||||
|
||||
Ensure now that you’ve set up your project to [autoload Composer-installed packages](https://getcomposer.org/doc/00-intro.md#autoloading).
|
163
resource-server-securing-api.md
Executable file
163
resource-server-securing-api.md
Executable file
@ -0,0 +1,163 @@
|
||||
---
|
||||
layout: default
|
||||
title: Securing your API
|
||||
permalink: /resource-server/securing-your-api/
|
||||
---
|
||||
|
||||
# Securing your API
|
||||
|
||||
## Setup
|
||||
|
||||
Wherever you intialise your objects, initialize a new instance of the resource server with the storage interfaces:
|
||||
|
||||
~~~ php
|
||||
$sessionStorage = new Storage\SessionStorage();
|
||||
$accessTokenStorage = new Storage\AccessTokenStorage();
|
||||
$clientStorage = new Storage\ClientStorage();
|
||||
$scopeStorage = new Storage\ScopeStorage();
|
||||
|
||||
$server = new ResourceServer(
|
||||
$sessionStorage,
|
||||
$accessTokenStorage,
|
||||
$clientStorage,
|
||||
$scopeStorage
|
||||
);
|
||||
~~~
|
||||
|
||||
|
||||
## Implementation
|
||||
|
||||
## Checking for valid access tokens
|
||||
|
||||
Before your API responds you need to check that an access token has been presented with the request (either in the query string `?access_token=abcdef` or as an authorization header `Authorization: Bearer abcdef`).
|
||||
|
||||
If you’re using a framework such as Laravel or Symfony you could use a route filter to do this. With the Slim framework you would use middleware.
|
||||
|
||||
This example uses Orno\Route:
|
||||
|
||||
~~~ php
|
||||
try {
|
||||
|
||||
// Check that an access token is present and is valid
|
||||
$server->isValidRequest();
|
||||
|
||||
// A successful response
|
||||
$response = $dispatcher->dispatch(
|
||||
$request->getMethod(),
|
||||
$request->getPathInfo()
|
||||
);
|
||||
|
||||
} catch (\League\OAuth2\Server\Exception\OAuthException $e) {
|
||||
|
||||
// Catch an OAuth exception
|
||||
$response = new Response(json_encode([
|
||||
'error' => $e->errorType,
|
||||
'message' => $e->getMessage()
|
||||
]), $e->httpStatusCode);
|
||||
|
||||
foreach ($e->getHttpHeaders() as $header) {
|
||||
$response->headers($header);
|
||||
}
|
||||
|
||||
} catch (\Orno\Http\Exception $e) {
|
||||
|
||||
// A failed response (thrown by code)
|
||||
$response = $e->getJsonResponse();
|
||||
$response->setContent(json_encode(['status_code' => $e->getStatusCode(), 'message' => $e->getMessage()]));
|
||||
|
||||
} catch (\Exception $e) {
|
||||
|
||||
// Other server error (500)
|
||||
$response = new Orno\Http\Response;
|
||||
$response->setStatusCode(500);
|
||||
$response->setContent(json_encode(['status_code' => 500, 'message' => $e->getMessage()]));
|
||||
|
||||
} finally {
|
||||
|
||||
// Return the response
|
||||
$response->headers->set('Content-type', 'application/json');
|
||||
$response->send();
|
||||
|
||||
}
|
||||
~~~
|
||||
|
||||
When `$server->isValidRequest()` is called the library will run the following tasks:
|
||||
|
||||
* Check if an access token is present in the query string
|
||||
* If not, check if an access token is contained in an `authorization` header.
|
||||
* If not, throw League\OAuth2\Server\Exception\InvalidAccessTokenException`
|
||||
* Check if the access token is valid with the database
|
||||
* If not, throw `League\OAuth2\Server\Exception\AccessDeniedException`
|
||||
* If the access token is valid:
|
||||
* Get the token's owner type (e.g. “user” or “client”) and their ID
|
||||
* Get a list of any scopes that are associated with the access token
|
||||
|
||||
Assuming an exception isn’t thrown you can then use the following functions in your API code:
|
||||
|
||||
* `getOwnerType()` - This will return the type of the owner of the access token. For example if a user has authorized another client to use their resources the owner type would be “user”.
|
||||
* `getOwnerId()` - This will return the ID of the access token owner. You can use this to check if the owner has permission to do take some sort of action (such as retrieve a document or upload a file to a folder).
|
||||
* `getClientId()` - Returns the ID of the client that was involved in creating the session that the access token is linked to.
|
||||
* `getAccessToken()` - Returns the access token used in the request.
|
||||
* `hasScope()` - You can use this function to see if a specific scope (or several scopes) has been associated with the access token. You can use this to limit the contents of an API response or prevent access to an API endpoint without the correct scope.
|
||||
* `getScopes()` - Returns all scopes attached to the access token.
|
||||
|
||||
## A simple example
|
||||
|
||||
This example endpoint will return a user’s information if a valid access token is present. If the access token has the `email` scope then the user's email address will be included in the response. Likewise if the `photo` scope is available the user's photo is included.
|
||||
|
||||
~~~ php
|
||||
$router->get('/users/{username}', function (Request $request, $args) use ($server) {
|
||||
|
||||
$result = (new Model\Users())->get($args['username']);
|
||||
|
||||
if (count($result) === 0) {
|
||||
throw new NotFoundException();
|
||||
}
|
||||
|
||||
$user = [
|
||||
'username' => $result[0]['username'],
|
||||
'name' => $result[0]['name']
|
||||
];
|
||||
|
||||
if ($server->hasScope('email')) {
|
||||
$user['email'] = $result[0]['email'];
|
||||
}
|
||||
|
||||
if ($server->hasScope('photo')) {
|
||||
$user['photo'] = $result[0]['photo'];
|
||||
}
|
||||
|
||||
return new Response(json_encode($user));
|
||||
});
|
||||
~~~
|
||||
|
||||
## Limiting an endpoint to a specific owner type
|
||||
|
||||
In this example, only a user’s access token is valid:
|
||||
|
||||
~~~ php
|
||||
if ($server->getOwnerType() !== 'user') {
|
||||
throw new Exception\AccessDeniedException;
|
||||
}
|
||||
~~~
|
||||
|
||||
## Limiting an endpoint to a specific owner type and scope
|
||||
|
||||
In this example, the endpoint will only respond to access tokens that are owner by client applications and that have the scope `users.list`.
|
||||
|
||||
~~~ php
|
||||
if ($server->getOwnerType() !== 'client' && $server->hasScope('users.list')) {
|
||||
throw new Exception\AccessDeniedException;
|
||||
}
|
||||
~~~
|
||||
|
||||
You might secure an endpoint in this way to only allow specific clients (such as your applications’ main website) access to private APIs.
|
||||
|
||||
## Return resource based on access token owner
|
||||
|
||||
~~~ php
|
||||
$photos = $model->getPhotos($server->getOwnerId());
|
||||
~~~
|
||||
|
||||
|
||||
Hopefully you can see how easy it is to secure an API with OAuth 2.0 and how you can use scopes to limit response contents or access to endpoints.
|
15
terminology.md
Executable file
15
terminology.md
Executable file
@ -0,0 +1,15 @@
|
||||
---
|
||||
layout: default
|
||||
title: Terminology
|
||||
permalink: /terminology/
|
||||
---
|
||||
|
||||
# Terminology
|
||||
|
||||
* `Access token` - A token used to access protected resources
|
||||
* `Authorization code` - An intermidiary token generated when a user authorizes a client to access protected resources on their behalf. The client receives this token and exchanges it for an access token.
|
||||
* `Authorization server` - A server which issues access tokens after successfully authenticating a client and resource owner, and authorizing the request.
|
||||
* `Client` - An application which accesses protected resources on behalf of the resource owner (such as a user). The client could hosted on a server, desktop, mobile or other device.
|
||||
* `Grant` - A grant is a method of acquiring an access token.
|
||||
* `Resource server` - A server which sits in front of protected resources (for example "tweets", users' photos, or personal data) and is capable of accepting and responsing to protected resource requests using access tokens.
|
||||
* `Scope` - A permission
|
Loading…
Reference in New Issue
Block a user