Code Monkey home page Code Monkey logo

omniauth-orcid's Introduction

OmniAuth ORCID

Gem Version Build Status Test Coverage Code Climate DOI

ORCID OAuth 2.0 Strategy for the OmniAuth Ruby authentication framework.

Provides basic support for connecting a client application to the Open Researcher & Contributor ID registry service.

Originally created for the ORCID example client application in Rails, then turned into a gem.

This gem is used in the DataCite-ORCID claiming tool and the Lagotto open source application for tracking events around articles and other scholarly outputs.

GrowKudos is a web app where the gem is in active use. There's a free registration during which (and after which) an ORCID can be connected via oAuth.

Installation

The usual way with Bundler: add the following to your Gemfile to install the current version of the gem:

gem 'omniauth-orcid'

Then run bundle install to install into your environment.

You can also install the gem system-wide in the usual way:

gem install omniauth-orcid

Getting started

Like other OmniAuth strategies, OmniAuth::Strategies::ORCID is a piece of Rack middleware. Please read the OmniAuth documentation for detailed instructions: https://github.com/intridea/omniauth.

There are three ways to register a client application and obtain client app credentials (client_id and client_secret) as well as a site URL:

  • for non-members (the default): Register your client application in the Developer Tools section of your ORCID profile.
  • for members (production): Register your client application here.
  • for development (sandbox): Register your client application here.

By default the module connects to the live ORCID service for non-members. All you have to provide are your client app credentials (see more here):

use OmniAuth::Builder do
  provider :orcid, ENV['ORCID_CLIENT_ID'], ENV['ORCID_CLIENT_SECRET']
end

To connect to the member API and/or sandbox, use the member and/or sandbox options, e.g.

use OmniAuth::Builder do
  provider :orcid, ENV['ORCID_CLIENT_ID'], ENV['ORCID_CLIENT_SECRET'], member: true, sandbox: true
end

omniauth-orcid sets the appropriate default scope depending on the member flag:

  • non-member: /authenticate
  • member: /read-limited /activities/update /person/update

You can override the scope via the scope query param.

OmniAuth takes care of the OAuth external-authentication handshake or "dance". All that the gem does is grab the identifier and tokens at the end of the dance and stick it into the OmniAuth hash which is subsequently accessible to your app via request.env['omniauth.auth'] (see AuthHashSchema). The hash looks something like this:

{
  "provider": "orcid",
  "uid": "0000-0003-2012-0010",
  "info": {
    "name": "John Smith",
    "email": "[email protected]",
    "first_name": "John",
    "last_name": "Smith",
    "location": "GB",
    "description": "John Smith is the ...",
    "urls": [
      { "Blog": "http://blog.martinfenner.org" }
    ]
  },
  "credentials": {
    "token": "e82938fa-a287-42cf-a2ce-f48ef68c9a35",
    "refresh_token": "f94c58dd-b452-44f4-8863-0bf8486a0071",
    "expires_at": 1979903874,
    "expires": true
  },
  "extra": {
    "raw_info": {
      "email": "[email protected]",
      "first_name": "John",
      "last_name": "Smith",
      "other_names": ["John Fitzgerald Smith"],
      "location": "GB",
      "description": "John Smith is the ...",
      "urls": [
        { "Blog": "http://blog.martinfenner.org" }
      ],
      "external_identifiers": [
        { "type": "GitHub",
          "value":"mfenner",
          "url": "https://github.com/mfenner" }
      ]
    }
  }
}

ject. Martin has a medical degree from the Free University of Berlin and is a Board-certified medical oncologist.", :location=>["DE"], :urls=>["http://blog.martinfenner.org"], :external_identifiers=>[{"type"=>"GitHub", "value"=>"mfenner", "url"=>"https://github.com/mfenner"}]} ........

You have to implement a callback handler to grab at least the uid from the hash and (typically) save it in a session. This effectively provides basic Log in with your ORCID functionality.

Most likely, with the token in hand, you'll want to do something more sophisticated with the API, like retrieving profile data and do something cool with it. See the Basic Tutorial: Read data on ORCID record for more details.

Here's how to get going with a couple of popular Rack-based frameworks:

Sinatra

Configure the strategy and implement a callback routine in your app:

require 'sinatra'
require 'sinatra/config_file'
require 'omniauth-orcid'
enable :sessions

use OmniAuth::Builder do
  provider :orcid, ENV['ORCID_CLIENT_ID'], ENV['ORCID_CLIENT_SECRET']
end
...
get '/auth/orcid/callback' do
  session[:omniauth] = request.env['omniauth.auth']
  redirect '/'
end

get '/' do

  if session[:omniauth]
    @orcid = session[:omniauth][:uid]
  end
  ..

The bundled demo.rb file contains an uber-simple working Sinatra example app. Spin it up, point your browser to http://localhost:4567/ and play:

gem install sinatra
ruby demo.rb
[2012-11-26 21:41:08] INFO  WEBrick 1.3.1
[2012-11-26 21:41:08] INFO  ruby 1.9.3 (2012-04-20) [x86_64-darwin11.3.0]
== Sinatra/1.3.2 has taken the stage on 4567 for development with backup from WEBrick
[2012-11-26 21:41:08] INFO  WEBrick::HTTPServer#start: pid=8383 port=4567

Rails

Add this to config/initializers/omniauth.rb to configure the strategy:

require 'omniauth-orcid'

Rails.application.config.middleware.use OmniAuth::Builder do
  provider :orcid, ENV['ORCID_CLIENT_ID'], ENV['ORCID_CLIENT_SECRET']
end

Register a callback path in 'config/routes.rb'

..
  match '/auth/:provider/callback' => 'authentications#create'
..

Implement a callback handler method in a controller:

class AuthenticationsController < ApplicationController
  ..
  def create
    omniauth = request.env["omniauth.auth"]
    session[:omniauth] = omniauth
    session[:params]   = params
    ..
  end

Or use omniauth-orcid with the Devise authentication solution.

# in config/initializers/devise.rb

config.omniauth :orcid, ENV['ORCID_CLIENT_ID'],
                        ENV['ORCID_CLIENT_SECRET'],
                        member: ENV['ORCID_MEMBER'],
                        sandbox: ENV['ORCID_SANDBOX']
# in app/models/user.rb

devise :omniauthable, :omniauth_providers => [:orcid]
# in config/routes.rb

Rails.application.routes.draw do
  devise_for :users, controllers: { omniauth_callbacks: "users/omniauth_callbacks" }

And then add custom logic in users/omniauth_callbacks.

More information

License

The MIT License (OSI approved, see more at http://www.opensource.org/licenses/mit-license.php)

Open Source Initiative Approved License

omniauth-orcid's People

Contributors

eleanorakh avatar gthorisson avatar mfenner avatar mmazour avatar nicolasfranck avatar yob avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

omniauth-orcid's Issues

Security vulnerability alert CVE-2015-9284

Because your gem has OmniAuth as a dependency, be aware of the security vulnerability alert CVE-2015-9284, https://nvd.nist.gov/vuln/detail/CVE-2015-9284 and then the epic discussions at omniauth/omniauth#809. Anyone who uses your gem will receive visible warning in their GitHub repo and as response with every push. While there doesn't seem to be a multi-platform solution to this vulnerability, sending POSTs in the token_method (and NOT GETs) is at least a start.

Using Hash#dig only works in Ruby 2.3.x or later

We ended up having to upgrade Ruby to use this gem because the method #dig is not present until the Ruby 2.3 series and later. We were running Ruby 2.2.x. Dig forced an upgrade to Ruby (which then forced an upgrade to Rails because of an Integer bug in the version of Rails on a newer Ruby version).

The documentation even shows the use of Ruby 1.9.3 (where Hash#dig doesn't work).

== Sinatra/1.3.2 has taken the stage on 4567 for development with backup from WEBrick
[2012-11-26 21:41:08] INFO  WEBrick::HTTPServer#start: pid=8383 port=4567

You may want to rethink using this new Hash core library feature if you want better compatibility with other versions of Ruby or else declare Ruby 2.3+ as a dependency for people looking to use the gem.

no scope in 1.1.4 version

Version 1.1.4 does not send scope, breaking authentication. Please revert to 1.1.1 until this is fixed.

Doubled SCRIPT_NAME when application is deployed to a sub-URI

I noticed when using the "orcid" strategy with a Rails application deployed to a sub-URI (e.g., www.example.com/sub-uri/), the script name is duplicated in the redirect_uri, (e.g., https://www.example.com/sub-uri/sub-uri/auth/orcid/callback). The definition of OmniAuth::Strategies::ORCID#callback_url includes script_name:

def callback_url
full_host + script_name + callback_path
end

But in OmniAuth::Strategy, #callback_path already includes script_name:

https://github.com/omniauth/omniauth/blob/d014c0e8af9ffa771f9f690d7313f46fdf5e94d0/lib/omniauth/strategy.rb#L445-L453

This was changed in omniauth/omniauth@c606a00.

Support omniauth-oauth2 1.4.0

I can see that in #1, this gem was changed to require omniauth-oauth2 1.3.1.

Since the breaking change in omniauth-oauth2 1.4.0 was released, it seems the omniauth-facebook and omniauth-google-oauth2 gems have released updates that continue to work.

The fix for omniauth-facebook looks like it wasn't too complicated - is there any chance the fix for this gem will be as simple?

default scope

I'm using omniauth-orcid-1.0.30.
According to CHANGELOG, the default scope is changed to "/authenticate" in 1.0. But it was reverted in
e28a931 . Is it an intended change?

MATCH deprecated ?

It seems that the match method has been deprecated. When I use this example in my app (Rails 5.0.0.1) , indeed I get an error :

=> Rails 5.0.0.1 application starting in development on http://localhost:3000
=> Run `rails server -h` for more startup options
Exiting
/var/lib/gems/2.3.0/gems/actionpack-5.0.0.1/lib/action_dispatch/routing/mapper.rb:78:in `check_via': You should not use the `match` method in your router without specifying an HTTP method. (ArgumentError)
If you want to expose your action to both GET and POST, add `via: [:get, :post]` option.
If you want to expose your action to GET, use `get` in the router:
  Instead of: match "controller#action"
  Do: get "controller#action"

(full output below)

If I add the GET and POST routes individually, the server starts - haven't checked if the actual auth works.

Is there support for Rails 5 ?

Thanks !
Bruce


Full output

=> Booting Puma
=> Rails 5.0.0.1 application starting in development on http://localhost:3000
=> Run `rails server -h` for more startup options
Exiting
/var/lib/gems/2.3.0/gems/actionpack-5.0.0.1/lib/action_dispatch/routing/mapper.rb:78:in `check_via': You should not use the `match` method in your router without specifying an HTTP method. (ArgumentError)
If you want to expose your action to both GET and POST, add `via: [:get, :post]` option.
If you want to expose your action to GET, use `get` in the router:
  Instead of: match "controller#action"
  Do: get "controller#action"
	from /var/lib/gems/2.3.0/gems/actionpack-5.0.0.1/lib/action_dispatch/routing/mapper.rb:1609:in `match'
	from /home/becker/Ops/AAROC/ASR-SGW/config/routes.rb:11:in `block in <top (required)>'
	from /var/lib/gems/2.3.0/gems/actionpack-5.0.0.1/lib/action_dispatch/routing/route_set.rb:389:in `instance_exec'
	from /var/lib/gems/2.3.0/gems/actionpack-5.0.0.1/lib/action_dispatch/routing/route_set.rb:389:in `eval_block'
	from /var/lib/gems/2.3.0/gems/actionpack-5.0.0.1/lib/action_dispatch/routing/route_set.rb:371:in `draw'
	from /home/becker/Ops/AAROC/ASR-SGW/config/routes.rb:1:in `<top (required)>'
	from /var/lib/gems/2.3.0/gems/activesupport-5.0.0.1/lib/active_support/dependencies.rb:287:in `load'
	from /var/lib/gems/2.3.0/gems/activesupport-5.0.0.1/lib/active_support/dependencies.rb:287:in `block in load'
	from /var/lib/gems/2.3.0/gems/activesupport-5.0.0.1/lib/active_support/dependencies.rb:259:in `load_dependency'
	from /var/lib/gems/2.3.0/gems/activesupport-5.0.0.1/lib/active_support/dependencies.rb:287:in `load'
	from /var/lib/gems/2.3.0/gems/railties-5.0.0.1/lib/rails/application/routes_reloader.rb:40:in `block in load_paths'
	from /var/lib/gems/2.3.0/gems/railties-5.0.0.1/lib/rails/application/routes_reloader.rb:40:in `each'
	from /var/lib/gems/2.3.0/gems/railties-5.0.0.1/lib/rails/application/routes_reloader.rb:40:in `load_paths'
	from /var/lib/gems/2.3.0/gems/railties-5.0.0.1/lib/rails/application/routes_reloader.rb:16:in `reload!'
	from /var/lib/gems/2.3.0/gems/railties-5.0.0.1/lib/rails/application/routes_reloader.rb:26:in `block in updater'
	from /var/lib/gems/2.3.0/gems/activesupport-5.0.0.1/lib/active_support/file_update_checker.rb:77:in `execute'
	from /var/lib/gems/2.3.0/gems/railties-5.0.0.1/lib/rails/application/routes_reloader.rb:27:in `updater'
	from /var/lib/gems/2.3.0/gems/railties-5.0.0.1/lib/rails/application/routes_reloader.rb:7:in `execute_if_updated'
	from /var/lib/gems/2.3.0/gems/railties-5.0.0.1/lib/rails/application/finisher.rb:119:in `block in <module:Finisher>'
	from /var/lib/gems/2.3.0/gems/railties-5.0.0.1/lib/rails/initializable.rb:30:in `instance_exec'
	from /var/lib/gems/2.3.0/gems/railties-5.0.0.1/lib/rails/initializable.rb:30:in `run'
	from /var/lib/gems/2.3.0/gems/railties-5.0.0.1/lib/rails/initializable.rb:55:in `block in run_initializers'
	from /usr/lib/ruby/2.3.0/tsort.rb:228:in `block in tsort_each'
	from /usr/lib/ruby/2.3.0/tsort.rb:350:in `block (2 levels) in each_strongly_connected_component'
	from /usr/lib/ruby/2.3.0/tsort.rb:431:in `each_strongly_connected_component_from'
	from /usr/lib/ruby/2.3.0/tsort.rb:349:in `block in each_strongly_connected_component'
	from /usr/lib/ruby/2.3.0/tsort.rb:347:in `each'
	from /usr/lib/ruby/2.3.0/tsort.rb:347:in `call'
	from /usr/lib/ruby/2.3.0/tsort.rb:347:in `each_strongly_connected_component'
	from /usr/lib/ruby/2.3.0/tsort.rb:226:in `tsort_each'
	from /usr/lib/ruby/2.3.0/tsort.rb:205:in `tsort_each'
	from /var/lib/gems/2.3.0/gems/railties-5.0.0.1/lib/rails/initializable.rb:54:in `run_initializers'
	from /var/lib/gems/2.3.0/gems/railties-5.0.0.1/lib/rails/application.rb:352:in `initialize!'
	from /home/becker/Ops/AAROC/ASR-SGW/config/environment.rb:5:in `<top (required)>'
	from /home/becker/Ops/AAROC/ASR-SGW/config.ru:3:in `require_relative'
	from /home/becker/Ops/AAROC/ASR-SGW/config.ru:3:in `block in <main>'
	from /var/lib/gems/2.3.0/gems/rack-2.0.1/lib/rack/builder.rb:55:in `instance_eval'
	from /var/lib/gems/2.3.0/gems/rack-2.0.1/lib/rack/builder.rb:55:in `initialize'
	from /home/becker/Ops/AAROC/ASR-SGW/config.ru:in `new'
	from /home/becker/Ops/AAROC/ASR-SGW/config.ru:in `<main>'
	from /var/lib/gems/2.3.0/gems/rack-2.0.1/lib/rack/builder.rb:49:in `eval'
	from /var/lib/gems/2.3.0/gems/rack-2.0.1/lib/rack/builder.rb:49:in `new_from_string'
	from /var/lib/gems/2.3.0/gems/rack-2.0.1/lib/rack/builder.rb:40:in `parse_file'
	from /var/lib/gems/2.3.0/gems/rack-2.0.1/lib/rack/server.rb:318:in `build_app_and_options_from_config'
	from /var/lib/gems/2.3.0/gems/rack-2.0.1/lib/rack/server.rb:218:in `app'
	from /var/lib/gems/2.3.0/gems/railties-5.0.0.1/lib/rails/commands/server.rb:59:in `app'
	from /var/lib/gems/2.3.0/gems/rack-2.0.1/lib/rack/server.rb:353:in `wrapped_app'
	from /var/lib/gems/2.3.0/gems/railties-5.0.0.1/lib/rails/commands/server.rb:124:in `log_to_stdout'
	from /var/lib/gems/2.3.0/gems/railties-5.0.0.1/lib/rails/commands/server.rb:77:in `start'
	from /var/lib/gems/2.3.0/gems/railties-5.0.0.1/lib/rails/commands/commands_tasks.rb:90:in `block in server'
	from /var/lib/gems/2.3.0/gems/railties-5.0.0.1/lib/rails/commands/commands_tasks.rb:85:in `tap'
	from /var/lib/gems/2.3.0/gems/railties-5.0.0.1/lib/rails/commands/commands_tasks.rb:85:in `server'
	from /var/lib/gems/2.3.0/gems/railties-5.0.0.1/lib/rails/commands/commands_tasks.rb:49:in `run_command!'
	from /var/lib/gems/2.3.0/gems/railties-5.0.0.1/lib/rails/commands.rb:18:in `<top (required)>'
	from bin/rails:4:in `require'
	from bin/rails:4:in `<main>'

Authentication error when using the sandbox api

When the OAuth callback is received from Orcid sandbox, I get the following error

ERROR -- omniauth: (orcid) Authentication failure! invalid_credentials:
OAuth2::Error, :
{"message-version":"1.2","orcid-profile":null,"orcid-search-results":null,
"error-desc":{"value":"Not found : No entity found for query"}}

I do have a user profile in both production and sandbox Orcid instances, but I guess my user id would be different in both.

Antonin Delpeuch very kindly pointed out that the profile details were being fetched from production and not sandbox. See message https://groups.google.com/d/msg/orcid-api-users/tWjaJpjtvRQ/VCQjogUzDAAJ for details

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.