GithubHelp home page GithubHelp logo

oauth2-provider's Introduction

Songkick::OAuth2::Provider

<img src=“https://secure.travis-ci.org/songkick/oauth2-provider.png?branch=master” alt=“Build Status” /> <img src=“https://codeclimate.com/badge.png” />

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.

It stores the clients and authorizations using ActiveRecord.

Installation

gem install songkick-oauth2-provider

A note on versioning

This library is based on draft-10, which was current when we began writing it. Having observed the development of the OAuth 2.0 spec over time, we have decided not to upgrade to later drafts until the spec is finalized. There is not enough meaningful change going on to merit migrating to every draft version - it would simply create a lot of turbulence and make it hard to reason about exactly what semantics the library supports.

During draft state, the gem version will indicate which draft it implements using the minor version, for example 0.10.2 means the second bug-fix release for draft 10.

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:

  • Some UI to register client applications

  • The OAuth request endpoint

  • A flow for logged-in users to grant access to clients

  • Resources protected by access tokens

Declare your app’s name

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

require 'songkick/oauth2/provider'
Songkick::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. Songkick::OAuth2::Provider can enforce this to make it easier to keep your users’ data secure.

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

  • The Songkick::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 Songkick::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 Songkick::OAuth2::Provider tables to your app’s schema. This is done using Songkick::OAuth2::Model::Schema.migrate, which will run all the gem’s migrations that have not yet been applied to your database.

Songkick::OAuth2::Model::Schema.migrate
I, [2012-10-31T14:52:33.801428 #7002]  INFO -- : Migrating to SongkickOauth2SchemaOriginalSchema (20120828112156)
==  SongkickOauth2SchemaOriginalSchema: migrating =============================
-- create_table(:oauth2_clients)
   -> 0.0029s
-- add_index(:oauth2_clients, [:client_id])
   -> 0.0009s
...

To rollback migrations, use Songkick::OAuth2::Model::Schema.rollback.

Model Mixins

There are two mixins you need to put in your code, Songkick::OAuth2::Model::ClientOwner for whichever model will own the “apps”, and Songkick::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:

class User < ActiveRecord::Base
  include Songkick::OAuth2::Model::ResourceOwner
  include Songkick::OAuth2::Model::ClientOwner
  has_many :interesting_pieces_of_data
end

Or they might go into two different models:

class User < ActiveRecord::Base
  include Songkick::OAuth2::Model::ResourceOwner
  has_many :interesting_pieces_of_data
end

class Company < ActiveRecord::Base
  include Songkick::OAuth2::Model::ClientOwner
  belongs_to :user
end

To see the methods and associations that these two mixins add to your models, take a look at lib/oauth2/model/client_owner.rb and lib/oauth2/model/resource_owner.rb.

Registering client applications

Clients are modeled by the Songkick::OAuth2::Model::Client class, which is an ActiveRecord model. You just need to implement a UI for creating them, for example in a Sinatra app:

get '/oauth/apps/new' do
  @client = Songkick::OAuth2::Model::Client.new
  erb :new_client
end

post '/oauth/apps' do
  @client = Songkick::OAuth2::Model::Client.new(params)
  @client.save ? erb(:show_client) : erb(:new_client)
end

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 Songkick::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 Songkick::OAuth2::Provider does not provide a response, you should render a page that lets the user begin to authenticate and grant access. This can happen in two cases:

  • The client makes a valid Authorization request. In this case you should display a login flow to the user so they can authenticate and grant access to the client.

  • The client makes an invalid Authorization request and the provider cannot redirect back to the client. In this case you should display an error page to the user, possibly including the value of @oauth2.error_description.

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:

[:get, :post].each do |method|
  __send__ method, '/oauth/authorize' do
    @owner  = User.find_by_id(session[:user_id])
    @oauth2 = Songkick::OAuth2::Provider.parse(@owner, env)

    if @oauth2.redirect?
      redirect @oauth2.redirect_uri, @oauth2.response_status
    end

    headers @oauth2.response_headers
    status  @oauth2.response_status

    if body = @oauth2.response_body
      body
    elsif @oauth2.valid?
      erb :login
    else
      erb :error
    end
  end
end

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:

<% @oauth2.params.each do |key, value| %>
  <input type="hidden" name="<%= key %>" value="<%= value %>">
<% end %>

You may also want to use scopes to provide granular access to your domain using scopes. The @oauth2 object exposes the scopes the client has asked for so you can display them to the user:

<p>The application <%= @oauth2.client.name %> wants the following permissions:</p>

<ul>
  <% @oauth2.scopes.each do |scope| %>
    <li><%= PERMISSION_UI_STRINGS[scope] %></li>
  <% end %>
</ul>

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:

post '/oauth/allow' do
  @user = User.find_by_id(session[:user_id])
  @auth = Songkick::OAuth2::Provider::Authorization.new(@user, params)

  if params['allow'] == '1'
    @auth.grant_access!
  else
    @auth.deny_access!
  end
  redirect @auth.redirect_uri, @auth.response_status
end

After granting or denying access, we just redirect back to the client using a URI that Songkick::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:

Songkick::OAuth2::Provider.handle_passwords do |client, username, password, scopes|
  user = User.find_by_username(username)
  if user.authenticate?(password)
    user.grant_access!(client, :scopes => scopes, :duration => 1.day)
  else
    nil
  end
end

The block receives the Client making the request, the username, password and a Set of the requested scopes. It 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 Songkick::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, the value of the assertion, which in this example will be a Facebook access token, and a Set of requested scopes.

Songkick::OAuth2::Provider.handle_assertions 'https://graph.facebook.com/me' do |client, assertion, scopes|
  facebook = URI.parse('https://graph.facebook.com/me?access_token=' + assertion)
  response = Net::HTTP.get_response(facebook)

  user_data = JSON.parse(response.body)
  account   = User.from_facebook_data(user_data)

  account.grant_access!(client, :scopes => scopes)
end

This code should run when your app boots, not during a request handler - think of it as configuration for Songkick::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:

get '/user/:username/notes' do
  user  = User.find_by_username(params[:username])
  token = Songkick::OAuth2::Provider.access_token(user, ['read_notes'], env)

  headers token.response_headers
  status  token.response_status

  if token.valid?
    JSON.unparse('notes' => user.notes)
  else
    JSON.unparse('error' => 'No notes for you!')
  end
end

Songkick::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 :implicit as the resource owner:

get '/me' do
  token = Songkick::OAuth2::Provider.access_token(:implicit, [], env)
  if token.valid?
    JSON.unparse('username' => token.owner.username)
  else
    JSON.unparse('error' => 'Keep out!')
  end
end

token.owner returns the ResourceOwner that issued the token. A token represents the fact that a single owner gave a single client a set of permissions.

License

Copyright © 2010-2012 Songkick.com

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.

oauth2-provider's People

Contributors

aledalgrande avatar attilagyorffy avatar brandonaaron avatar danlucraft avatar dwo avatar evbuk1 avatar gregates avatar harigopal avatar jasondavies avatar jcoglan avatar jjb avatar josephwilk avatar lann avatar lvonk avatar pixeltrix avatar sgerrand avatar theotherstupidguy avatar vivienbarousse avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

oauth2-provider's Issues

RFC 6749 support

OAuth 2.0 seems to have been finalized into RFC 6749. Is there any current effort to adapt this project from draft 10 to the published standard?

Publish to Rubygems

It's a bad practice to use directly source code coming from github in a production app.
Source code should be packaged into a gem and published to Rubygems.

Still maintained/supported?

We are still using Songkick OAuth2 provider in production...
We are doing the Rails upgrade and wondering if we should abandon it...

Password grant type does not accept scope param when there is no existing authorization

When the resource owner has no existing authorization record and they attempt to get a token via the password grant (and scopes are specified), the Exchange class creates an authorization with a nil scope value and the following error is returned:

error = invalid_scope
error_description = The request scope was never granted by the user

A review of the code indicates this is likely an issue with the assertion type too.

I began to write a fix but then noticed line 182 in the exchange_spec.rb

https://github.com/songkick/oauth2-provider/blob/master/spec/oauth2/provider/exchange_spec.rb#L182

OAuth2::Provider.handle_passwords do |client, username, password|
  user = TestApp::User[username]
  if password == 'soldier'
    user.grant_access!(client, :scopes => ['foo', 'bar'])
  else
    nil
  end
end

handle_passwords and handle_assertions implementations don't have access to the scope in params. I couldn't find anything in the spec about not allowing one to specify scopes on password and assertion grant types. If they did, they could pass the given scope to grant_access!

Is this a legit bug or am I embarrassingly simple?

Flow error corner case

From looking at the examples and docs, it would seem the recommended use it to have two action end points, say /authorize and /authorize/allow. The first would receive connections from both the user's agent and from clients, while the second would receive connections from the user'agent authorizing or not a client.

In the case of /authorize it appears one should use OAuth2::Provider.parse to route the request, which determines whether the request for authorization or exchange by looking for the grant_type param.

The examples then use the redirect? method on the object that Provider.parse returns to determine whether to cause the redirect. If there was no redirect, the output of the response_body method is used determine whether the reply to the requestor directly using JSON or to render the view that asks the user whether to authorize the client or not.

OAuth2::Provider::Authorization will cause a redirect in almost all error situations. The one exception is if client_id is invalid. Presumably you are not using the request's redirect uri param in that case, as it would create an open redirector. But this means that if client_id is invalid response_body will return JSON, which will be displayed to the user.

Similarly, if SSL enforcement has been turned on and for some reason the user agent connects to the /authorize end point over HTTP rather than HTTPS, OAuth2::Provider.parse will return a OAuth2::Provider::Error, which responds to redirect? with false and to response_body with JSON. This would then be displayed to the user.

Seems like there is a need to distinguish responses meant for the client, which are in JSON, and responses for the user agent, which need to be passed to the view for rendering, and response_body is not fully filling that purpose. For now I am checking the class of the object returned by OAuth2::Provider.parse, and if no redirect was indicated, when showing the view if the class is Authorization, and otherwise responding with whatever respond_body return.

Not sure if this is the best approach.

Wondering if this wrapper works on Rails 2.3.14 & Ruby 1.8.7

Hi there! I'm asking this because I implemented this on a ror 2.3.14 project without any issues at first, but seams the the problem is when I try to retrieve the token. This is how is implemented following the example:

Routes availables

 /apps/authorize [get, post]
 /apps/allow [post]
 /apps/login [post]

I got the feeling that something is missing for the token (regarding I handle in the /apps/authorize route with the parameter request_type=token

in the authorize action I have

 @owner = ( current_user.nil? ) ? nil : current_user
 @oauth2 = OAuth2::Provider.parse(@owner, request.env)

 if @oauth2.redirect? && @oauth2.error.blank?
    redirect_to @oauth2.redirect_uri, :status => @oauth2.response_status
    return
 end

 if @oauth2.response_body.blank?
    render and return
 elsif @oauth2.valid?
    render :action => "login" and return
 else
    redirect_to root_path
 end

I got everything working but i can't solve the issue how to retrieve the token

I missing something or maybe is not compatible with this rails version or ruby (for instance the force_ssl I can't use because of the version of rails)

If anyone could point me if I'm missing something or anything I'll really appreciate it, I run out of ideas

Thanks a lot
Cheers

Can Omniauth be integrated with this?

We have a REST API and a Backbone web app, with smartphone apps to come. We'd like to secure the API with OAuth, but also keep the social login functionality we currently have.

Our question is, how should Omniauth (which we're using to provide that FB, Twitter, Google etc. login functionality) authentication be integrated with this API authorisation?

We've seen the "assertions" support which looks useful, but aren't sure how to go about using it.

Multiple instances of the same client_id invalidate access tokens

I don't see this addressed in the draft (10 or later versions). This is the only reference I can find on the issue: http://tools.ietf.org/html/draft-richer-oauth-instance-00

Let's say I have some browser add-on installed on my laptop and that same add-on installed on my desktop. If I go through a user agent flow on my desktop to get a token.

http://local/oauth2/authorize?client_id=b06jrfu82u3adi9ludzfnb1ik&redirect_uri=http://www.clientsite.org/q&scope=read create&response_type=token

Everything is fine. But when I do the same flow on my laptop, the access token my desktop has is now replaced.

Is there something additional I'm missing or is this a failing in the draft (10)?

POSTing JSON returning a bad 400 Bad Request on /oauth/authorize

So I am running into a problem right now using a JSON Post to authorize that always seems to return a 400 Bad Request status.

I am setting the content type to application/json for the JSON Post.

{ "username": "[email protected]", "password": "changeme",
"client_id": "[client_id]",
"client_secret":"[client_secret]",
"grant_type":"password",
"redirect_uri":"http://api.lvh.me:3000/oauth/callback"
}

but if I just do a regular POST with key value pairs, it works perfectly.

curl -X POST http://api.lvh.me:3000/oauth/authorize \
  -H "Content-Type: application/json" \
  -d 'client_id=[client_id]' \
  -d 'client_secret=[client=secret]' \
  -d 'redirect_uri=http://api.lvh.me:3000/oauth/callback' \
  -d 'grant_type=password' \
  -d '[email protected]' \
  -d 'password=changeme'

Is there something that I am missing when I try to use JSON instead?
Here is my oauth/authorize command.

def authorize
    exchange = Songkick::OAuth2::Provider.parse(nil, request)
    logger.info exchange.inspect

    if exchange.redirect?
      redirect_to exchange.redirect_uri, status: exchange.response_status
    else
      response.headers.update(exchange.response_headers)
      render text: exchange.response_body, status: exchange.response_status 
    end
  end

Example app missing POST /oauth/token

First of all, good job fine sir.

I was looking at the example app and trying to make a consumer for it using Omniauth (specifically, the omniauth-oauth2 gem). However, during the callback process, the Omniauth strategy sends a POST request to the provider at /oauth/token, and it's getting a 404 response which blows up everything.

From what I've been reading, that endpoint is supposed to verify the code that is sent and return the access_token, so that the full authorization cycle is completed. However that logic isn't there and I couldn't find anything in the documentation to point me in the right direction.

I assume I'd need to add something like:

post '/oauth/token' do
  @auth = Songkick::OAuth2::Model::Authorization.find_by_code(params[:code])

  return halt 400 unless @auth
  @auth.generate_access_token if @auth.expired?

  JSON.unparse({
    'access_token'  => @auth.access_token,
    'token_type'    => 'Bearer',
    'expires_in'    => @auth.expires_in,
    'refresh_token' => @auth.refresh_token
  })
end

Or will hell break loose if I do that?

set refresh token when grant type is `code`

When a client issues a authorize request with response_type=code, authorize server gives an access_token without expires_in or refresh_token value even if grant_access! method is called with duration option.

I've tested this situation with following scenario.

  1. Client makes a GET request with URL = http://oauth_server.dev/oauth/authorize?client_id=xxx&redirect_uri=http://client.dev/cb&response_type=code
  2. In sever's authorize action, renders an application allowance form
  3. In server's allow action, OAuth2::Provider::Authorization is constructed with @user and params with params[:client_id], params[:response_type], params[:redirect_uri]. Then it calls grants_access!(:duration => 3600) and redirect to client's redirect_uri with code parameter.
  4. In client, client issue a POST request to http://oauth_server.dev/oauth/access_token with params[:grant_type] = "code", params[:code] = xxx, params[:client_id]=yyy and params[:client_secret]=zzz and The authorization server gives response with valid access_token but not refresh_token or expires_in values. I think those values should be in response.

In oauth2/model/authorization.rb, exchange! method just set refresh_token with nil with no condition check.

def exchange!
  self.code          = nil
  self.access_token  = self.class.create_access_token
  self.refresh_token = nil
  save!
end

I think it should check whether expires_in parameter is set, and have to generate refresh_token in that case.

Encrypted Client Secret

Any particular reason why you encrypt client secrets? Pretty much all the OAuth sites I've see allow the developer to see their secret later on, e.g. to configure a new client implementation

Rails 3.2.3 Mass Assignment Issue in Authorizations

Hi there,

In my Rails 3.2 controller action when I use the following code:

@auth = OAuth2::Provider::Authorization.new(resource, params)
@auth.grant_access!

I am getting the following exception:

ActiveModel::MassAssignmentSecurity::Error (Can't mass-assign protected attributes: owner, client):
app/controllers/users/registrations_controller.rb:14:in `create'

I believe this is because in Rails 3.2.3 there was a security change that sees attribute mass assignment change from defaulting to off if no attr_accessible is declared.

Has anyone else encountered this?

Client Secret

I've seen (or I think I've seen) other OAuth provider implementations that don't hash the client secret. Is this something that's within the spec, or is it done here for extra security?

no refresh_token by default

In the file /lib/songkick/oauth2/model/authorization.rb

 def exchange!
          self.code          = nil
          self.access_token  = self.class.create_access_token
          self.refresh_token = nil
          save!
        end

what is the reason not to generate refresh_token?

How to provide access from authorization code?

Hello all,

I can't find anywhere in the code and documentation how to provide a access token from an authorization code.

omniauth-oauth2 use a authorization code and then request a token from it.

I've tried to use the Exchange but could succed

Tables aren't created

Nice work on this app!

Since the tables weren't created by default, it might be easier for others using this example to have a rake task or some automatic mechanism by which they're setup. Eventually, I got it to work by doing this:
cd example ruby schema.rb

Thanks!
Chip

Native Application workflow

Hi,

We're looking to get oauth2-provider working for a native application:
http://tools.ietf.org/id/draft-ietf-oauth-v2-27.html#rfc.section.9

This is mentioned very vaguely in draft 10 but in later drafts they mention that the server can communicate the oauth token back through seting a cookie such as auth_token:
https://developers.google.com/accounts/docs/MobileApps

We figure in order to implement this we would need to have the option on OAuth2::Model::Client to either force there to be a redirect_uri (as it works right now) OR a bool flag for use_cookie or native.

We're going to fork the project to get the job done for us but wanted your input on how we could do this so it could get merged back in as a feature. If you've been considering adding other Client Profiles, let us know about those considerations so our implementation of Native Application can jive with it.

Access token changing / Same client different tokens

I've noticed that the access_token changes on subsequent requests to authorize an client for a given user results in overwriting the old access_token.

From what I gather from this post, this is a result of a gap in the spec.

What is the recommended approach to handling a situation where we expect users to use the same client from multiple devices?

Thanks a lot in advance.

Infinite query loop when attempt to grant_access to same client for same user subsequently

I am still exploring both oauth and oauth2-provider currently. In my specific use case, I have a login with facebook on mobile app side. I intend to use assertions, since they seem to be the most relevant way to login the user using facebook credentials.

I have noticed that if a user grants access to an app once again, which has a valid token existing, the frameworks get into an infinite loop.

For example I create a resource owner User model and App as the Client. A simple query like below in irb shell will show you, then when it is fired twice one after other, the second one results in an infinite query loop.

User.first.grant_access!(Songkick::OAuth2::Model::Client.first, :response_type => "token")

I intend to return an access token from the authorization object. But should I put explicit checks before calling this code that a valid token exist or not. Moreoever looks like we store only the hash of access_token in database, so I can't return client that for sure. Should I expire that explicitly and create a new one to return?

If those checks are needed on application part then it is ok, however I want to make sure that they are needed.

Example for Rails

It would be useful to see an example using this gem with Rails 3.2. Does such a thing exist?

undefined method `ssl?' for #<Rack::Request >

in my Rails 3.0 app, I found once I have enforce_ssl set to true in initializer, I am getting this error on request:

NoMethodError (undefined method ssl?' for #<Rack::Request:0x7f973655c588>): .rvm/gems/ruby-1.8.7-p302@aspen/bundler/gems/oauth2-provider-0d9fcdf58b56/lib/oauth2/router.rb:68:indetect_transport_error'
.rvm/gems/ruby-1.8.7-p302@aspen/bundler/gems/oauth2-provider-0d9fcdf58b56/lib/oauth2/router.rb:13:in parse' .rvm/gems/ruby-1.8.7-p302@aspen/bundler/gems/oauth2-provider-0d9fcdf58b56/lib/oauth2/provider.rb:103:inparse'

I don't see ssl? method in Rack::Request either, is this gem relying on some other gems to provide ssl detection?

Getting token information

Hi,

Thanks for building this library. Found it quite easy to integrate with my project thus far.

My question is: Given that I only have an access_token (because using a Javascript client, I'm sending a user to the authorize endpoint and the user has already previously authorized my app), is there any way for me to retrieve the refresh token and expires_in values for it?

I suppose I can create a separate endpoint that returns these values to my client, but I'm wondering if there is already a built-in easier way.

Thanks,

Lloyd

Missing License

What license are you going to distribute this source code under?

Provider.parse doesn't like RSpec env.

Whenever I try to authenticate in my specs, I can get a code just fine with:

@auth = Songkick::OAuth2::Provider::Authorization.new(@user, params)

However, when I try to get the access_token:

@oauth2 = Songkick::OAuth2::Provider.parse(@user, env)

it consistently fails. It seems the Router, after making this call:

request = request_from(env)

strips out the parameters, so the next call:

params = request.params

is always an empty hash.

Am I doing something wrong?

I can make the same calls using curl and everything works just fine. The RSpec mock environment seems to cause problems. Is that by design?

Broken example as per RFC 6749

In the example/application.rb the expected initial request as given in the commented line is:

# /oauth/authorize?response_type=token&client_id=...

With RFC 6749 section 4.1.1 , the only allowable response_type is code.

I'm using Omniauth-OAuth2 which seems to adhere to the current RFC standard which won't allow the response_type to be changed to anything else. This has affected the flow in the example/application.rb.

Reference: http://stackoverflow.com/questions/6354262/omniauth-cant-change-response-type-to-token-in-strategy

bcrypt-ruby is now just bcrypt

I see the following dependencies:

songkick-oauth2-provider (0.10.2)
      activerecord
      bcrypt-ruby
      json
      rack

And I get this warning:

The bcrypt-ruby gem has changed its name to just bcrypt.  Instead of installing `bcrypt-ruby`, you should install `bcrypt`.  Please update your dependencies accordingly.

Example application throws TypeError

Hi,

I've dived into the example application straight away and when trying to register a new application in the following path I got a TypeError:

TypeError at /oauth/apps/new can't convert nil into Integer file: base.rb location: Integer line: 896

Now I've got to admit that I hardly have that much experience with Sinatra that I wish I would so I'm posting this straight up here. In order to be able to reproduce the issue you would do the following:

Please let me know if I'm doing anything wrong.

My environment is set up with the following:

ruby --version
=> ruby 1.9.3p194 (2012-04-20 revision 35410) [x86_64-darwin12.0.0]
bundle --version
=> Bundler version 1.2.0.pre.1

Redirect URIs with query strings are handled incorrrectly

As per the spec, query strings are allowed in the redirect_uri. However, in the Authorization Provider, we append a querystring (with a ?) regardless of whether one already exists in the registered redirect_uri.

This means given a registered redirect_uri of http://example.com?hello, the user agent is given a redirect to http://example.com/?hello?code=5m2ca7ipl4r7pm509dhtekm78mw1qm1&scope=.

It would appear that we either have to parse the existing querystring and merge in our new parameters, or append to the redirect_uri with an & instead of an ?, if a querystring already exists (simpler, but does not handle edge cases as well).

If you agree with this assessment, I can make a patch.

Update draft version?

On the README says that the current implementation is based on draft 10.

I just wanted to be sure this is not a typo, as the current OAuth2 draft is 24.

Thanks!

Resource owner not found authorizes automatically?

Is there a good reason why passing a nil resource owner to OAuth2::Provider::AccessToken validates?

https://github.com/songkick/oauth2-provider/blob/master/lib/songkick/oauth2/provider/access_token.rb#L59

You have an explicit test for it here:
https://github.com/songkick/oauth2-provider/blob/master/spec/songkick/oauth2/provider/access_token_spec.rb#L55

So I'm assuming it was deliberate. Here's my scenario:

oauth2-provider is a separate service. It lives in another app from the resources being accessed. It maintains all the authorizations and resource owners.

Since AccessToken finds any access token that matches the hash:
https://github.com/songkick/oauth2-provider/blob/master/lib/songkick/oauth2/provider/access_token.rb#L49

an attacker with an access token granted to him by User A (for all intents and purposes, that could be the attacker himself), could cause an auth request to be made for a bogus user User Fake, using the token he has from User A. The resource owner would then be nil, the token would exist and oauth2-provider would validate his token and let him proceed.

The workaround for my case seems to be to return a 404 if the resource owner can't be determined, but I was curious why oauth2-provider assumes everything is ok when resource owner is nil.

Plans to update to RFC 6749?

Per the comment on #61 back in September of last year, the note in the README is up-to-date in that the gem still only implements draft-10.

Are there plans to update this gem to the full RFC? Or does someone need to pick up that task?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.