OAuth2::Provider

This gem provides a toolkit for adding OAuth2 provider capabilities to a
Ruby web app. It handles most of the protocol for you: it is designed to
provide a sufficient level of abstraction that it can implement updates to
the protocol without affecting your application code at all. All you have
to deal with is authenticating your users and letting them grant access to
client apps.

It is also designed to be usable within any web frontend, at least those of
Rails and Sinatra. Its API uses Rack request-environment hashes rather than
framework-specific request objects, though you can pass those in and their
request.env property will be used internally.

Terminology

Client: A third-party software system that integrates with the
provider. Twitter and Facebook call this an “app”.

Client Owner: The entity which owns a client, i.e. the
individual or company responsible for the client application.

Resource Owner: This will almost certainly be a User. It's the
entity which has the data that the client is asking permission to
see.

Authorization: When a resource owner grants access to a
client (i.e., a user grants access to a company's app), an
authorization is created. This can typically be revoked by the user at any
time (which is the strength and flexibility of the OAuth architecture).

Access Token: An opaque string representing an authorization.
A client is given an access token when a resource owner
grants it access to resources. The access token must be included in all
requests for protected resources.

Usage

A basic example is in example/application.rb. To implement OAuth,
you need to provide four things:

Installing the gem

If you are not using Bundler, put the library in your load path and require
it:

require 'oauth2/provider'

Declare your app's name

Declare your app's name somewhere (for example in Rails, in
application.rb or an initializer):

OAuth2::Provider.realm = 'My OAuth app'

HTTPS

Your application should ensure that any endpoint that receives or returns
OAuth data is only accessible over a secure transport such as the
https: protocol. OAuth2::Provider can enforces this to
make it easier to keep your users' data secure.

You can set OAuth2::Provider.enforce_ssl = true in the same place
that you declared your app name above. This will result in the following
behavior:

The OAuth2::Provider.parse method will produce error responses and
will not process the incoming request unless the request was made using the
https: protocol.

An access token constructed using OAuth2::Provider.access_token
will return false for #valid? unless the request was made
using the https: protocol.

Any access token received over an insecure connection is immediately
destroyed to prevent eavesdroppers getting access to the user's
resources. A client making an insecure request will have to send the user
through the authorization process again to get a new token.

Schema

Add the OAuth2::Provider tables to your app's schema. This is
done using OAuth2::Model::Schema.up, which can be used inside an
ActiveRecord migration like so:

class CreateOauth2ProviderModels < ActiveRecord::Migration
def up
OAuth2::Model::Schema.up
end
def down
OAuth2::Model::Schema.down
end
end

Model Mixins

There are two mixins you need to put in your code,
OAuth2::Model::ClientOwner for whichever model will own the
“apps”, and OAuth2::Model::ResourceOwner for whichever model is
the innocent, unassuming entity who will selectively share their data.
It's possible that this is the same model, such as User:

Client applications must have a name and a redirect_uri:
provide fields for editing these but do not allow the other fields to be
edited, since they are the client's access credentials. When you've
created the client, you should show its details to the user registering the
client: its name, redirect_uri, client_id and
client_secret (the last two are generated for you).
client_secret is not stored in plain text so you can only read it
when you initially create the client object.

OAuth request endpoint

This is a path that your application exposes in order for clients to
communicate with your application. It is also the page that the client will
send users to so they can authenticate and grant access. Many requests to
this endpoint will be protocol-level requests that do not involve the user,
and OAuth2::Provider gives you a generic way to handle all that.

You should use this to get the right response, status code and headers to
send to the client. In the event that OAuth2::Provider does not
provide a response, you should render a page that lets the user begin to
authenticate and grant access.

This endpoint must be accessible via GET and POST. In this example we will
expose the OAuth service through the path /oauth/authorize. We
check if there is a logged-in resource owner and give this to
OAuth::Provider, since we may be able to immediately redirect if
the user has already authorized the client:

There is a set of parameters that you will need to hold on to for when your
app needs to redirect back to the client. You could store them in the
session, or pass them through forms as the user completes the flow. For
example to embed them in the login form, do this:

You can also use the method @oauth2.unauthorized_scopes to get the
list of scopes the user has not already granted to the client, in the case
where the client already has some authorization. If no prior authorization
exists between the user and the client,
@oauth2.unauthorized_scopes just returns all the scopes the client
has asked for.

Granting access to clients

Once the user has authenticated you should show them a page to let them
grant or deny access to the client application. This is straightforward;
let's say the user checks a box before posting a form to indicate their
intent:

After granting or denying access, we just redirect back to the client using
a URI that OAuth2::Provider will provide for you.

Using password credentials

If you like, OAuth lets you use a user's login credentials to
authenticate with a provider. In this case the client application must
request these credentials directly from the user and then post them to the
exchange endpoint. On the provider side you can handle this using the
handle_passwords and grant_access! API methods, for
example:

The block must return user.grant_access!(client) if you want to
allow access, otherwise it should return nil.

Using assertions

Assertions provide a way to access your OAuth services using user
credentials from another service. When using assertions, the user will not
authenticate on your web site; the OAuth client will authenticate the user
using some other framework and obtain a token, then exchange this token for
an access token on your domain.

For example, a client application may let a user authenticate using
Facebook, so the application obtains a Facebook access token from the user.
The client would then pass this token to your OAuth endpoint and exchange
it for an access token from your site. You will typically create an account
in your database to represent this, then have that new account grant access
to the client.

To use assertions, you must tell OAuth2::Provider how to handle
assertions based on their type. An assertion type must be a valid URI. For
the Facebook example we'd do the following. The block yields the
Client object making the exchange request, and the value of the
assertion, which in this example will be a Facebook access token.

This code should run when your app boots, not during a request handler -
think of it as configuration for OAuth2::Provider. The framework
will invoke it when a client attempts to use assertions with your OAuth
endpoint.

The final call in your handler should be to grant_access!; this
returns an Authorization object that the framework then uses to
complete the response to the client. If you want to deny the request for
whatever reason, the block must return nil. If a client tries to
use an assertion type you have no handler for, the client will get an error
response.

Protecting resources with access tokens

To protect the user's resources you need to check for access tokens.
This is simple, for example a call to get a user's notes:

OAuth2::Provider.access_token() takes a ResourceOwner, a
list of scopes required to access the resource, and a request environment
object. If the token was not granted for the required scopes, has expired
or is simply invalid, headers and a status code are set to indicate this to
the client. token.valid? is the call you should use to determine
whether to serve the request or not.

It is also common to provide a dynamic resource for getting some basic data
about a user by supplying their access token. This can be done by passing
nil as the resource owner:

License

Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the “Software”),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.