This section is intended to be used in one of two ways.
The first option is that you can start reading someone else's documentation and then refer back to here
every time you run across a term that you do not immediately understand.
The second option is that you can read this section straight through for a reasonably detailed
explanation of the OAuth 2 protocol, with all terms explained. In fact if you choose this option, you
will find it explained in more detail than you need to be a successful consumer.
However if you use it in the second way, please be advised that this does not try to be a complete and
exact explanation of the specification. In particular the specification requires specific error handling
from the service provider that I have glossed over, and allows for extra types of requests that I also
glossed over. (Particularly the bit about how any serviceprovider at any time can add any new method
that they want so long as they invent a new grant_type for it.)
consumer
The consumer is the one who needs to be authorized by OAuth 2 to be able to "consume" an API. If
you're reading this document, that's likely to be you.
client
The software on the consumer's side which actually will access the API. From a consumer's point of
view, a consumer and the client are usually the same thing. But, in fact, a single consumer may
actually write multiple clients. And if one is a web application while another is a command line
program, the differences can matter to how OAuth 2 will work.
Where I have a choice in this document I say consumer rather than client because that term is less
likely overloaded in most organizations.
user
The user is the entity (person or company) who wishes to let the consumer access their account.
Resource Owner
What the OAuth 2 specification calls the user, to focus attention on the fact that they own the data
which will get accessed.
I chose to say user instead of ResourceOwner because that is my best guess as to what the consumer
is most likely to already call them.
service provider
The serviceprovider is the one which hosts the account, restricts access and offers the API. For
example, Google.
Resource Server
In the OAuth 2 specification, this is the service run by the serviceprovider which hosts provides an
API to the user's data. The name has deliberate symmetry with ResourceOwner.
Authorization Server
In the OAuth 2 specification, this is the service run by the serviceprovider which is responsible
for granting access to the ResourceServer.
The consumer does not need to care about this distinction, but it exposes an important fact about how
the serviceprovider is likely to be structured internally. You typically will have one team that is
responsible for granting access, tracking down clients that seem abusive, and so on. And then many
teams are free to create useful stuff and write APIs around them, with authorization offloaded to the
first team.
As a consumer, you will make API requests to the ResourceServer signed with proof of auhorization
from the AuthorizationServer, the ResourceServer will confirm authorization with the AuthorizationServer, and then the ResourceServer will do whatever it was asked to do.
Organizing internal responsibilities in this manner makes it easier for many independent teams in a
large company to write public APIs.
client type
The serviceprovider internally tags each client with a clienttype which tells it something about
what environment it is in, and how it interacts with the user. Are are the basic types listed in RFC
6749 <http://tools.ietf.org/html/rfc6749#section-2.1>:
web application
Runs on a web server. Is expected to keep secrets. Likely to be appropriate for a Perl client.
user-agent-based application
JavaScript application running in a browser that wants to make AJAX calls. Can't keep secrets.
Does not make sense for A Perl client.
native application
Application installed on a user's machine. Can't keep secrets. Possibly appropriate for a Perl
client.
Of course all of this is up to the serviceprovider. For example at the time of this writing, Google
documents no less than six clienttypes at <https://developers.google.com/accounts/docs/OAuth2>, none
of which have been given the above names. (They also call them "Scenarios" rather than clienttype.)
They rename the top two, split nativeapplication into two based on whether your application controls
a browser, and add two new ones.
flow
Your flow is the sequence and methods of interactions that set up authorization. The flow depends on
your serviceprovider and clienttype. For example the serviceprovider might redirect the user to a
URL controlled by a web application, while instead for a native application the user is told to cut
and paste a code somewhere.
Despite flow being more common terminology in OAuth 2, clienttype is more self-explanatory, so I've
generally gone with that instead.
client_id
The client_id is a public ID that tells the serviceprovider about the client that is accessing it.
That is, it says both who the consumer is, and what the clienttype is. Being public, the client_id
can be shared with the user. The details of how this is assigned are between the consumer and the
serviceprovider.
client_secret
The client_secret is a somewhat private piece of information that the consumer can pass to the
serviceprovider to prove that the request really comes from the consumer. How much this is trusted,
and how it is used, will depend on the clienttype and serviceprovider.
redirect_uri
The serviceprovider needs a way to tell the user how to pass information back to the consumer in a
secure way. That is provided by the redirect_uri which can be anything from a "https://..." URL that
the consumer controls to an instruction that lets the serviceprovider know that it should tell the
user to cut and paste some information.
It is up to the serviceprovider what values of are acceptable for the redirect_uri, and whether it
is a piece of information that is remembered or passed in during the authorization process.
state
The state is an optional piece of information that can be created by the consumer then added to all
requests as an extra piece of protection against forgery. (You are supposed to create a random piece
of information for each request, then check that you get it back.) In the OAuth 2 specification it
is optional, but recommended. Depending on the combination of your serviceprovider and clienttype,
it may be required.
scope
The scope describes what permissions are to be granted. To get multiple permissions, you need to
join the permissions requested with spaces. Everything else is up to the serviceprovider.
Inside of the serviceprovider, what likely happens is that the team which runs a given ResourceServer tells the team running the AuthorizationServer what permissions to their API should be
called. And then the AuthorizationServer can limit a given consumer to just the APIs that the user
authorized them for.
Authorization Endpoint
The AuthorizationEndpoint is the URL provided by the serviceprovider for the purpose of sending
requests to authorize the consumer to access the user's account. This is part of the AuthorizationServer.
response_type
The response_type tells the serviceprovider what kind of information it is supposed to pass back. I
am not aware of a case where a Perl client could usefully use any value other than "code". However
there are flows where other things happen. For example the flow for the user-agent-basedapplicationclienttype uses a response_type of token.
While the field is not very useful for Perl clients, it is required in the specification. So you
have to pass it.
authorization_url
This is the URL on the serviceprovider's website that the user goes to in order to let the serviceprovider know what authorization is being requested.
It is constructed as the AuthorizationEndpoint with get parameters added for the response_type,
client_id, and optionally state. The specification mentions both redirect_uri and scope but does not
actually mandate that they be accepted or required. However they may be. And, of course, a given
service provider can add more parameters at will, and require (or not) different things by clienttype.
An example URL for Google complete with optional extensions is
<https://accounts.google.com/o/oauth2/auth?scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.email+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.profile&state=%2Fprofile&redirect_uri=https%3A%2F%2Foauth2-login-demo.appspot.com%2Fcode&response_type=code&client_id=812741506391.apps.googleusercontent.com&approval_prompt=force>
In LWP::Authen::OAuth2 the "authorization_url" method constructs this URL. If your request needs to
include the state, scope, or any serviceprovider specific parameter, you need to pass those as
parameters. The others are usefully defaulted from the service provider and object.
(authorization) code
If the response_type is set to "code" (which should be the case), then on success the serviceprovider will generate a one use authorizationcode to give to the user to take back to the consumer.
Depending on the flow this could happen with no effort on the part of the user. For example the user
can be redirected to the redirect_uri with the code passed as a get parameter. The web server would
then pick these up, finish the handshake, and then redirect the user elsewhere.
In all interactions where it is passed it is simply called the code. But it is described in one
interaction as an authorization_code.
Token Endpoint
The TokenEndpoint is the URL provided by the serviceprovider for the purpose of sending requests
from the consumer to get tokens allowing access to the user's account.
grant_type
The grant_type is the type of grant you expected to get based on the response_type requested in the
authorization_url. For a response_type of "code" (which is almost certainly what will be used with
any consumer written in Perl), the grant_type has to be "authorization_code". If they were being
consistent, then that would be code like it is everywhere else, but that's what the spec says.
We will later encounter the grant_type "refresh_token". The specification includes potential
requests that can be in a flow that might prove useful. However you are only likely to encounter
that if you are subclassing LWP::Authen::OAuth2::ServiceProvider. In that case you will hopefully
discover the applicability and details of those grant_types from the serviceprovider's
documentation.
Access Token Request
Once the consumer has a code the consumer can submit an AccessTokenRequest by sending a POST
request to the TokenEndpoint with the grant_type, code, client_id, client_secret, redirect_uri and
(if in the authorization code) the state. Your serviceprovider can also require you to authenticate
in any further way that they please. You will get back a JSON response.
An example request might look like this:
POST /o/oauth2/token HTTP/1.1
Host: accounts.google.com
Content-Type: application/x-www-form-urlencoded
code=4/P7q7W91a-oMsCeLvIaQm6bTrgtp7&
client_id=8819981768.apps.googleusercontent.com&
client_secret={client_secret}&
redirect_uri=https://oauth2-login-demo.appspot.com/code&
grant_type=authorization_code
and the response if you're lucky will look something like:
HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
Cache-Control: no-store
Pragma: no-cache
{
"access_token":"1/fFAGRNJru1FTz70BzhT3Zg",
"expires_in":3920,
"token_type":"Bearer",
"refresh_token":"1/xEoDL4iW3cxlI7yDbSRFYNG01kVKM2C-259HOF2aQbI"
}
or if you're unlucky, maybe like this:
HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
Cache-Control: no-store
Pragma: no-cache
{
"error":"invalid_grant"
}
Success is up to the serviceprovider which can decide not to give you tokens for any reason that
they want, including that you asked twice, they think the user might be compromised, they don't like
the client, or the phase of the Moon. (I am not aware of any serviceprovider that makes failure
depend on the phase of the Moon, but the others are not made up.)
The "request_tokens" method of LWP::Authen::OAuth2 will make this request for you, read the JSON and
create the token or tokens. If you passed in a "save_tokens" callback in constructing your object,
that will be called for you to store the tokens. On future API calls you can retrieve that to skip
the handshake if possible.
token_type
The token_type is a case insensitive description of the type of token that you could be given. In
theory there is a finite list of types that you could encounter. In practice serviceproviders can
add more at any time, either intentionally or unintentionally by failing to correctly implement the
one that they claimed to have created.
See LWP::Authen::OAuth2::AccessToken for advice on how to add support for a new or incorrectly
implemented token_type.
expires_in
The number of seconds until you will need a new token because the old one should have expired.
LWP::Authen::OAuth2 provides the "should_refresh" method to let you know when you need that new
token. (It actually starts returning true slightly early to avoid problems if clocks are not
synchronized, or you begin a series of operations.)
access_token
An access_token is a temporary token that gives the consumer access to the user's data in the serviceprovider's system. In the above response the "access_token" is the value of the token, "expires_in"
is the number of seconds it is good for in theory (practice tends to be close but not always exact),
and "token_type" specifies how it is supposed to be used.
Once the authorization handshake is completed, if the access_token has a supported token_type. then
LWP::Authen::OAuth2 will automatically sign any requests for you.
Bearer token
If the token_type is "bearer" (case insensitive), then you should have a bearertoken as described by
RFC 6750 <http://tools.ietf.org/html/rfc6750>. For as long as the token is good, any request signed
with it is authorized. Signing is as simple as sending an https request with a header of:
Authorization: Bearer 1/fFAGRNJru1FTz70BzhT3Zg
You can also sign by passing "access_token=..." as a post or get parameter, though the specification
recommends against using a get parameter. If you are using LWP::Authen::OAuth2, then it is signed
with the header.
refresh_token
The above example also included a refresh_token. If you were given one, you can use it later to ask
for a refreshed access_token. Whether you get one is up to your serviceprovider, who is likely to
decide that based on your client_type.
Refresh Access Token
If you have a refresh_token, you can at any time send a RefreshAccessToken request. This is a POST
to the TokenEndpoint with the refresh_token, client_id and client_secret arguments. You also have
to send a grant_type of "refresh_token".
Thus in the above case we'd send
POST /o/oauth2/token HTTP/1.1
Host: accounts.google.com
Content-Type: application/x-www-form-urlencoded
refresh_token=1/xEoDL4iW3cxlI7yDbSRFYNG01kVKM2C-259HOF2aQbI&
client_id=8819981768.apps.googleusercontent.com&
client_secret={client_secret}&
grant_type=refresh_token
and if lucky could get a response like
HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
Cache-Control: no-store
Pragma: no-cache
{
"access_token":"ya29.AHES6ZSiArSow0zeKokajrri5gMBpGc6Sq",
"expires_in":3600,
"token_type":"Bearer",
}
and if unlucky could get an error as before.
In LWP::Authen::OAuth2 this request is made for you transparently behind the scenes if possible. If
you're curious when, look in the source for the "refresh_access_token" method. There are also
optional callbacks that you can pass to let you save the tokens, or hijack the refresh method for
your own purposes. (Such as making sure that only one process tries to refresh tokens even though
many are accessing it.)
But note that not all flows offer a refresh_token. If you're on one of those flows then you need to
send the user back to the serviceprovider for authorization renewal. From the user's point of view
this is likely to be painless because it will be done with transparent redirects. But the consumer
needs to be aware of it.