├── .gitignore ├── .travis.yml ├── Gemfile ├── LICENSE ├── README.md ├── Rakefile ├── devise-token_authenticatable.gemspec ├── lib ├── devise-token_authenticatable.rb └── devise │ ├── token_authenticatable.rb │ └── token_authenticatable │ ├── model.rb │ ├── strategy.rb │ └── version.rb └── spec ├── factories ├── admin.rb └── user.rb ├── models └── devise │ └── token_authenticatable │ └── model_spec.rb ├── requests └── devise │ └── token_authenticatable │ └── strategy_spec.rb ├── spec_helper.rb ├── support ├── helpers.rb ├── integration.rb ├── rails_app │ ├── Rakefile │ ├── app │ │ ├── controllers │ │ │ ├── admins │ │ │ │ └── sessions_controller.rb │ │ │ ├── admins_controller.rb │ │ │ ├── application_controller.rb │ │ │ ├── home_controller.rb │ │ │ ├── publisher │ │ │ │ ├── registrations_controller.rb │ │ │ │ └── sessions_controller.rb │ │ │ └── users_controller.rb │ │ ├── mailers │ │ │ └── users │ │ │ │ └── mailer.rb │ │ ├── models │ │ │ ├── admin.rb │ │ │ └── user.rb │ │ └── views │ │ │ └── users │ │ │ └── index.html.erb │ ├── config.ru │ ├── config │ │ ├── application.rb │ │ ├── boot.rb │ │ ├── database.yml │ │ ├── environment.rb │ │ ├── initializers │ │ │ ├── backtrace_silencers.rb │ │ │ ├── devise.rb │ │ │ ├── inflections.rb │ │ │ ├── secret_token.rb │ │ │ └── session_store.rb │ │ └── routes.rb │ ├── db │ │ ├── migrate │ │ │ └── 20100401102949_create_tables.rb │ │ └── schema.rb │ └── public │ │ ├── 404.html │ │ ├── 422.html │ │ ├── 500.html │ │ └── favicon.ico └── session_helper.rb └── token_authenticatable_spec.rb /.gitignore: -------------------------------------------------------------------------------- 1 | *.gem 2 | *.rbc 3 | *.log 4 | .bundle 5 | .config 6 | .rspec 7 | .rspec-local 8 | .ruby-version 9 | .yardoc 10 | Gemfile.lock 11 | InstalledFiles 12 | _yardoc 13 | coverage 14 | doc/ 15 | lib/bundler/man 16 | pkg 17 | rdoc 18 | spec/reports 19 | test/tmp 20 | test/version_tmp 21 | tmp 22 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: ruby 2 | rvm: 3 | - 2.1.10 4 | - 2.2.10 5 | - 2.3.8 6 | - 2.4.5 7 | - 2.5.0 8 | - 2.6.2 9 | 10 | before_install: 11 | - gem install bundler -v 1.17.3 12 | 13 | script: bundle exec rspec 14 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | # Specify your gem's dependencies in devise-token_authenticatable.gemspec 4 | gemspec 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2013 Sebastian Oelke 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Devise::TokenAuthenticatable 2 | 3 | [![Tag](https://img.shields.io/github/tag/baschtl/devise-token_authenticatable.svg?style=flat-square)](https://github.com/baschtl/devise-token_authenticatable/releases) [![Build Status](https://img.shields.io/travis/baschtl/devise-token_authenticatable.svg?style=flat-square)](https://travis-ci.org/baschtl/devise-token_authenticatable) [![Code Climate](https://img.shields.io/codeclimate/github/baschtl/devise-token_authenticatable.svg?style=flat-square)](https://codeclimate.com/github/baschtl/devise-token_authenticatable) 4 | 5 | This gem provides the extracted Token Authenticatable module of devise. It includes the functionality that was also in [version 3.1.2](https://github.com/plataformatec/devise/tree/v3.1.2) of devise. With the inclusion of this module a user is able to sign in via an authentication token. This token can be given via a query string or HTTP Basic Authentication. See the hint below to understand which version of this gem supports which version of devise. 6 | 7 | Use this gem as a starting point for your own token authentication mechanism for devise. Furthermore, if you need token authentication in connection with newer devise releases this gem might be an appropriate solution, too. 8 | 9 | ## Installation 10 | 11 | Add this line to your application's Gemfile: 12 | 13 | gem 'devise-token_authenticatable' 14 | 15 | And then execute: 16 | 17 | $ bundle 18 | 19 | Or install it yourself as: 20 | 21 | $ gem install devise-token_authenticatable 22 | 23 | ### Which version to use for which version of devise? 24 | 25 | *devise-token_authenticatable* | *devise* 26 | -------------------------------:|--------- 27 | `~> 0.1` | `~> 3.2.0` 28 | `~> 0.2` | `~> 3.3.0` 29 | `~> 0.3` | `~> 3.4.0` 30 | `~> 0.4.0`, `< 0.4.9` | `~> 3.5.0`, `< 3.5.2` 31 | `~> 0.4.9` | `~> 3.5.2` 32 | `~> 0.5.x`, `<= 1.0.2` | `>= 4.0.0`, `< 4.6.0` 33 | `~> 1.1.0` | `>= 4.0.0`, `< 5.0.0` 34 | 35 | ## Usage 36 | Create needed columns with corresponding migration: 37 | 38 | ```ruby 39 | def change 40 | add_column :users, :authentication_token, :text 41 | add_column :users, :authentication_token_created_at, :datetime 42 | 43 | add_index :users, :authentication_token, unique: true 44 | end 45 | ``` 46 | 47 | Add `:token_authenticatable` to your devise model: 48 | 49 | ```ruby 50 | class User < ActiveRecord::Base 51 | devise :database_authenticatable, :token_authenticatable 52 | end 53 | ``` 54 | 55 | ## Configuration 56 | 57 | This gem can be configured as shown in the following: 58 | 59 | ```ruby 60 | Devise::TokenAuthenticatable.setup do |config| 61 | # enables the expiration of a token after a specified amount of time, 62 | # requires an additional field on the model: `authentication_token_created_at` 63 | # defaults to nil 64 | config.token_expires_in = 1.day 65 | 66 | # set the authentication key name used by this module, 67 | # defaults to :auth_token 68 | config.token_authentication_key = :other_key_name 69 | 70 | # enable reset of the authentication token before the model is saved, 71 | # defaults to false 72 | config.should_reset_authentication_token = true 73 | 74 | # enables the setting of the authentication token - if not already - before the model is saved, 75 | # defaults to false 76 | config.should_ensure_authentication_token = true 77 | end 78 | ``` 79 | 80 | Enable devise's HTTP Auth for the token strategy as shown below: 81 | 82 | ```ruby 83 | # initializers/devise.rb 84 | Devise.setup do |config| 85 | # ... 86 | config.http_authenticatable = true 87 | # or 88 | config.http_authenticatable = [:token] 89 | # ... 90 | end 91 | ``` 92 | 93 | ## Troubleshooting 94 | 95 | ##### Using a new user's auth token does not result in invalidating an old users session. How can I ignore session storage when using token authentication? 96 | 97 | Add `:token_auth` to your devise configuration: 98 | 99 | ```ruby 100 | Devise.setup do |config| 101 | config.skip_session_storage = [:http_auth, :token_auth] 102 | end 103 | ``` 104 | 105 | ## Documentation 106 | 107 | For your convenience there is also a [source code documentation](http://rubydoc.info/github/baschtl/devise-token_authenticatable/master/frames). 108 | 109 | ## Contributing 110 | 111 | 1. Fork it. 112 | 2. Create your feature branch (`git checkout -b my-new-feature`). 113 | 3. Commit your changes (`git commit -am 'Add some feature'`). 114 | 4. Push to the branch (`git push origin my-new-feature`). 115 | 5. Create new Pull Request. 116 | 6. Get a thank you! 117 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require "bundler/gem_tasks" 2 | -------------------------------------------------------------------------------- /devise-token_authenticatable.gemspec: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | lib = File.expand_path('../lib', __FILE__) 3 | $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) 4 | require 'devise/token_authenticatable/version' 5 | 6 | Gem::Specification.new do |spec| 7 | spec.name = "devise-token_authenticatable" 8 | spec.version = Devise::TokenAuthenticatable::VERSION.dup 9 | spec.platform = Gem::Platform::RUBY 10 | spec.authors = ["Sebastian Oelke"] 11 | spec.email = ["dev@soelke.de"] 12 | spec.description = %q{This gem provides the extracted Token Authenticatable module of devise. 13 | It enables the user to sign in via an authentication token. This token 14 | can be given via a query string or HTTP Basic Authentication.} 15 | spec.summary = %q{Provides authentication based on an authentication token for devise 3.2 and up.} 16 | spec.homepage = "https://github.com/baschtl/devise-token_authenticatable" 17 | spec.license = "MIT" 18 | 19 | spec.files = `git ls-files`.split($/) 20 | spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) } 21 | spec.test_files = spec.files.grep(%r{^(test|spec|features)/}) 22 | spec.require_paths = ["lib"] 23 | 24 | 25 | spec.add_dependency "devise", ">= 4.0.0", "< 5.0.0" 26 | 27 | spec.add_development_dependency "rails", "~> 4.2" 28 | spec.add_development_dependency "rspec-rails", "~> 3.0" 29 | spec.add_development_dependency "pry", "~> 0.10" 30 | spec.add_development_dependency "factory_girl_rails", "~> 4.4" 31 | spec.add_development_dependency "timecop", "~> 0.7" 32 | spec.add_development_dependency "bundler", "~> 1.17" 33 | 34 | # Fix database connection with sqlite3 and jruby 35 | if RUBY_ENGINE == 'ruby' 36 | # Match rails's expected version constraint 37 | spec.add_development_dependency "sqlite3", "~> 1.3.6" 38 | elsif RUBY_ENGINE == 'jruby' 39 | spec.add_development_dependency "activerecord-jdbcsqlite3-adapter" 40 | end 41 | end 42 | -------------------------------------------------------------------------------- /lib/devise-token_authenticatable.rb: -------------------------------------------------------------------------------- 1 | require 'devise/token_authenticatable' 2 | -------------------------------------------------------------------------------- /lib/devise/token_authenticatable.rb: -------------------------------------------------------------------------------- 1 | require "devise/token_authenticatable/strategy" 2 | 3 | module Devise 4 | module TokenAuthenticatable 5 | 6 | # Authentication token params key name of choice. E.g. /users/sign_in?some_key=... 7 | mattr_accessor :token_authentication_key 8 | @@token_authentication_key = :auth_token 9 | 10 | # Token expiration period. E.g. 1.day 11 | mattr_accessor :token_expires_in 12 | @@token_expires_in = nil 13 | 14 | # Defines if the authentication token is reset before the model is saved. 15 | mattr_accessor :should_reset_authentication_token 16 | @@should_reset_authentication_token = false 17 | 18 | # Defines if the authentication token is set - if not already - before the model is saved. 19 | mattr_accessor :should_ensure_authentication_token 20 | @@should_ensure_authentication_token = false 21 | 22 | # Enable the configuration of the TokenAuthenticatable 23 | # strategy with a block: 24 | # 25 | # Devise::TokenAuthenticatable.setup do |config| 26 | # config.token_authentication_key = :other_key 27 | # end 28 | # 29 | def self.setup 30 | yield self 31 | end 32 | end 33 | end 34 | 35 | # Register TokenAuthenticatable module in Devise. 36 | Devise::add_module :token_authenticatable, 37 | model: 'devise/token_authenticatable/model', 38 | strategy: true, 39 | no_input: true 40 | -------------------------------------------------------------------------------- /lib/devise/token_authenticatable/model.rb: -------------------------------------------------------------------------------- 1 | module Devise 2 | module Models 3 | # The +TokenAuthenticatable+ module is responsible for generating an authentication token and 4 | # validating the authenticity of the same while signing in. 5 | # 6 | # This module only provides a few helpers to help you manage the token, but it is up to you 7 | # to choose how to use it. 8 | # 9 | # If you want to delete the token after it is used, you can do so in the 10 | # after_token_authentication callback. 11 | # 12 | # == APIs 13 | # 14 | # If you are using token authentication with APIs and using trackable. Every 15 | # request will be considered as a new sign in (since there is no session in 16 | # APIs). You can disable this by creating a before filter as follow: 17 | # 18 | # before_filter :skip_trackable 19 | # 20 | # def skip_trackable 21 | # request.env['devise.skip_trackable'] = true 22 | # end 23 | # 24 | module TokenAuthenticatable 25 | extend ActiveSupport::Concern 26 | 27 | included do 28 | before_save :reset_authentication_token_before_save 29 | before_save :ensure_authentication_token_before_save 30 | 31 | attr_writer :token_expires_in 32 | end 33 | 34 | module ClassMethods 35 | 36 | def find_for_token_authentication(conditions) 37 | auth_conditions = conditions.dup 38 | authentication_token = auth_conditions.delete(Devise::TokenAuthenticatable.token_authentication_key) 39 | 40 | find_for_authentication( 41 | auth_conditions.merge(authentication_token: authentication_token) 42 | ) 43 | end 44 | 45 | # Generate a token checking if one does not already exist in the database. 46 | def authentication_token 47 | loop do 48 | token = Devise.friendly_token 49 | break token unless to_adapter.find_first({ authentication_token: token }) 50 | end 51 | end 52 | 53 | end 54 | 55 | def self.required_fields(klass) 56 | fields = [:authentication_token] 57 | 58 | unless Devise::TokenAuthenticatable.token_expires_in.blank? 59 | fields.push(:authentication_token_created_at) 60 | end 61 | 62 | fields 63 | end 64 | 65 | # Generate new authentication token (a.k.a. "single access token"). 66 | def reset_authentication_token 67 | self.authentication_token = self.class.authentication_token 68 | self.authentication_token_created_at = Time.now unless token_expires_in.blank? 69 | end 70 | 71 | # Generate new authentication token and save the record. 72 | def reset_authentication_token! 73 | reset_authentication_token 74 | save(validate: false) 75 | end 76 | 77 | # Generate authentication token unless already exists. 78 | def ensure_authentication_token 79 | reset_authentication_token if authentication_token.blank? 80 | end 81 | 82 | # Generate authentication token unless already exists and save the record. 83 | def ensure_authentication_token! 84 | reset_authentication_token! if authentication_token.blank? 85 | end 86 | 87 | # Hook called after token authentication. 88 | def after_token_authentication 89 | end 90 | 91 | def token_expires_in 92 | Devise::TokenAuthenticatable.token_expires_in 93 | end 94 | 95 | private 96 | 97 | def reset_authentication_token_before_save 98 | reset_authentication_token if Devise::TokenAuthenticatable.should_reset_authentication_token 99 | end 100 | 101 | def ensure_authentication_token_before_save 102 | ensure_authentication_token if Devise::TokenAuthenticatable.should_ensure_authentication_token 103 | end 104 | end 105 | end 106 | end 107 | -------------------------------------------------------------------------------- /lib/devise/token_authenticatable/strategy.rb: -------------------------------------------------------------------------------- 1 | require 'devise/strategies/base' 2 | 3 | module Devise 4 | module Strategies 5 | # 6 | # The +TokenAuthenticatable+ strategy was extracted from Devise 3.1.0. Its purpose is 7 | # to provide the deprecated functionality of the +TokenAuthenticatable+ strategy. The 8 | # following description was adapted accordingly. 9 | # 10 | # See: https://github.com/plataformatec/devise/blob/v3.1/lib/devise/strategies/token_authenticatable.rb 11 | # 12 | # 13 | # Strategy for signing in a user, based on a authenticatable token. This works for both params 14 | # and http. For the former, all you need to do is to pass the params in the URL: 15 | # 16 | # http://myapp.example.com/?user_token=SECRET 17 | # 18 | # For headers, you can use basic authentication passing the token as username and 19 | # blank password. Since some clients may require a password, you can pass "X" as 20 | # password and it will simply be ignored. 21 | # 22 | # You may also pass the token using the Token authentication mechanism provided 23 | # by Rails: http://api.rubyonrails.org/classes/ActionController/HttpAuthentication/Token.html 24 | # The token options are stored in request.env['devise.token_options'] 25 | # 26 | class TokenAuthenticatable < Authenticatable 27 | def store? 28 | super && !mapping.to.skip_session_storage.include?(:token_auth) 29 | end 30 | 31 | def valid? 32 | super || valid_for_token_auth? 33 | end 34 | 35 | def authenticate! 36 | resource = mapping.to.find_for_token_authentication(authentication_hash) 37 | return fail(:invalid_token) unless resource 38 | 39 | unless token_expires_in.blank? 40 | if Time.now > (resource.authentication_token_created_at + token_expires_in.to_i) 41 | return fail(:expired_token) 42 | end 43 | end 44 | 45 | if validate(resource) 46 | resource.after_token_authentication 47 | success!(resource) 48 | end 49 | end 50 | 51 | private 52 | 53 | # Token Authenticatable can be authenticated with params in any controller and any verb. 54 | def valid_params_request? 55 | true 56 | end 57 | 58 | # Check if the model accepts this strategy as token authenticatable. 59 | def token_authenticatable? 60 | mapping.to.http_authenticatable?(:token) 61 | end 62 | 63 | # Check if this is strategy is valid for token authentication by: 64 | # 65 | # * Validating if the model allows http token authentication; 66 | # * If the http auth token exists; 67 | # * If all authentication keys are present; 68 | # 69 | def valid_for_token_auth? 70 | token_authenticatable? && auth_token.present? && with_authentication_hash(:token_auth, token_auth_hash) 71 | end 72 | 73 | # Extract the auth token from the request 74 | def auth_token 75 | @auth_token ||= ActionController::HttpAuthentication::Token.token_and_options(request) 76 | end 77 | 78 | # Extract a hash with attributes:values from the auth_token 79 | def token_auth_hash 80 | request.env['devise.token_options'] = auth_token.last 81 | { authentication_keys.first => auth_token.first } 82 | end 83 | 84 | # Try both scoped and non scoped keys 85 | def params_auth_hash 86 | if params[scope].kind_of?(Hash) && params[scope].has_key?(authentication_keys.first) 87 | params[scope] 88 | else 89 | params 90 | end 91 | end 92 | 93 | # Overwrite authentication keys to use token_authentication_key. 94 | def authentication_keys 95 | @authentication_keys ||= [Devise::TokenAuthenticatable.token_authentication_key] 96 | end 97 | 98 | def token_expires_in 99 | @token_expires_in ||= Devise::TokenAuthenticatable.token_expires_in 100 | end 101 | end 102 | end 103 | end 104 | 105 | Warden::Strategies.add(:token_authenticatable, Devise::Strategies::TokenAuthenticatable) 106 | -------------------------------------------------------------------------------- /lib/devise/token_authenticatable/version.rb: -------------------------------------------------------------------------------- 1 | module Devise 2 | module TokenAuthenticatable 3 | VERSION = '1.1.0'.freeze 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /spec/factories/admin.rb: -------------------------------------------------------------------------------- 1 | FactoryGirl.define do 2 | 3 | factory :admin do 4 | sequence(:email) { |n| "admin#{n}@domain.com" } 5 | password 'some_password' 6 | password_confirmation 'some_password' 7 | 8 | ignore do 9 | confirm_account true 10 | end 11 | 12 | after(:create) do |u, evaluator| 13 | u.confirm if evaluator.confirm_account 14 | end 15 | 16 | trait :with_reset_password_token do 17 | reset_password_token { SecureRandom.hex } 18 | end 19 | 20 | trait :with_authentication_token do 21 | authentication_token { SecureRandom.hex } 22 | end 23 | end 24 | end 25 | -------------------------------------------------------------------------------- /spec/factories/user.rb: -------------------------------------------------------------------------------- 1 | FactoryGirl.define do 2 | 3 | factory :user do 4 | username 'testuser' 5 | sequence(:email) { |n| "user#{n}@domain.com" } 6 | password 'some_password' 7 | password_confirmation 'some_password' 8 | facebook_token { SecureRandom.hex } 9 | 10 | ignore do 11 | confirm_account true 12 | end 13 | 14 | after(:create) do |u, evaluator| 15 | u.confirm if evaluator.confirm_account 16 | end 17 | 18 | trait :with_reset_password_token do 19 | reset_password_token { SecureRandom.hex } 20 | end 21 | 22 | trait :with_authentication_token do 23 | authentication_token { SecureRandom.hex } 24 | authentication_token_created_at { Time.now } 25 | end 26 | 27 | trait :with_day_old_token do 28 | authentication_token { SecureRandom.hex } 29 | authentication_token_created_at { Time.now - 1.day } 30 | end 31 | end 32 | end 33 | -------------------------------------------------------------------------------- /spec/models/devise/token_authenticatable/model_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | ## 4 | # If a model that is token authenticatable should be tested with 5 | # this shared example the corresponding factory has to provide a trait 6 | # +:with_authentication_token+ that sets the attribute +authentication_token+. 7 | # 8 | # See spec/factories/user.rb for an example. 9 | # 10 | shared_examples "token authenticatable" do 11 | context "instance methods" do 12 | describe "#reset_authentication_token" do 13 | let(:entity) { create(described_class.name.underscore.to_sym, :with_authentication_token) } 14 | 15 | subject { entity.reset_authentication_token } 16 | 17 | it "should reset authentication token" do 18 | expect { subject }.to change { entity.authentication_token } 19 | end 20 | 21 | context "token created at" do 22 | it "should reset" do 23 | swap Devise::TokenAuthenticatable, token_expires_in: 1.hour do 24 | expect { subject }.to change { entity.authentication_token_created_at } 25 | end 26 | end 27 | 28 | it "should not reset when token expires in not set" do 29 | expect { subject }.to_not change { entity.authentication_token_created_at } 30 | end 31 | end 32 | end 33 | 34 | describe "#ensure_authentication_token" do 35 | subject { entity.ensure_authentication_token } 36 | 37 | context "with existing authentication token" do 38 | let(:entity) { create(described_class.name.underscore.to_sym, :with_authentication_token) } 39 | 40 | it "should not change the authentication token" do 41 | expect { subject }.to_not change { entity.authentication_token } 42 | end 43 | 44 | it "should not change the authentication token created at" do 45 | expect { subject }.to_not change { entity.authentication_token_created_at } 46 | end 47 | end 48 | 49 | context "without existing authentication token and authentication token created at" do 50 | let(:entity) { create(described_class.name.underscore.to_sym) } 51 | 52 | before :each do 53 | entity.authentication_token = nil 54 | entity.authentication_token_created_at = nil 55 | end 56 | 57 | it "should set an authentication token" do 58 | expect { subject }.to change { entity.authentication_token } 59 | end 60 | 61 | context "token created at" do 62 | it "should set" do 63 | swap Devise::TokenAuthenticatable, token_expires_in: 1.hour do 64 | expect { subject }.to change { entity.authentication_token_created_at } 65 | end 66 | end 67 | 68 | it "should not set when token expires in disabled" do 69 | expect { subject }.to_not change { entity.authentication_token_created_at } 70 | end 71 | end 72 | end 73 | end 74 | end 75 | 76 | context "class methods" do 77 | describe "#find_for_authentication_token" do 78 | let(:entity) { create(described_class.name.underscore.to_sym, :with_authentication_token) } 79 | 80 | it "should authenticate a valid entity with authentication token and return it" do 81 | authenticated_entity = described_class.find_for_token_authentication(auth_token: entity.authentication_token) 82 | expect(entity.authentication_token).to eq(authenticated_entity.authentication_token) 83 | end 84 | 85 | it "should authenticate with all the options passed in, not just the auth_token" do 86 | conditions = {facebook_token: entity.facebook_token, auth_token: entity.authentication_token} 87 | expected_conditions = {facebook_token: entity.facebook_token, authentication_token: entity.authentication_token} 88 | 89 | expect(described_class).to receive(:find_for_authentication).with(expected_conditions).and_call_original 90 | 91 | described_class.find_for_token_authentication(conditions) 92 | end 93 | 94 | it "should return nil when authenticating an invalid entity by authentication token" do 95 | authenticated_entity = described_class.find_for_token_authentication(auth_token: entity.authentication_token.reverse) 96 | expect(authenticated_entity).to be_nil 97 | end 98 | 99 | it "should not be subject to injection" do 100 | create(described_class.name.underscore.to_sym, :with_authentication_token) 101 | 102 | authenticated_entity = described_class.find_for_token_authentication(auth_token: { '$ne' => entity.authentication_token }) 103 | expect(authenticated_entity).to be_nil 104 | end 105 | end 106 | 107 | describe "#required_fields" do 108 | it "should contain the fields that Devise uses when token expires in disabled" do 109 | expect(Devise::Models::TokenAuthenticatable.required_fields(described_class)).to eq([ 110 | :authentication_token 111 | ]) 112 | end 113 | 114 | it "should contain the fields that Devise uses" do 115 | swap Devise::TokenAuthenticatable, token_expires_in: 1.hour do 116 | expect(Devise::Models::TokenAuthenticatable.required_fields(described_class)).to eq([ 117 | :authentication_token, :authentication_token_created_at 118 | ]) 119 | end 120 | end 121 | end 122 | 123 | end 124 | 125 | context "before_save" do 126 | let(:entity) { create(described_class.name.underscore.to_sym, :with_authentication_token) } 127 | 128 | context "when the authentication token should be reset" do 129 | before :each do 130 | Devise::TokenAuthenticatable.setup do |config| 131 | config.should_reset_authentication_token = true 132 | end 133 | end 134 | 135 | after :each do 136 | Devise::TokenAuthenticatable.setup do |config| 137 | config.should_reset_authentication_token = false 138 | end 139 | end 140 | 141 | it "resets the authentication token" do 142 | expect(entity).to receive(:reset_authentication_token).once 143 | 144 | entity.update_attributes(created_at: Time.now) 145 | end 146 | end 147 | 148 | context "when the authentication token should not be reset" do 149 | it "does not reset the authentication token" do 150 | expect(entity).to_not receive(:reset_authentication_token) 151 | 152 | entity.update_attributes(created_at: Time.now) 153 | end 154 | end 155 | 156 | context "when the authentication token should be ensured" do 157 | before :each do 158 | Devise::TokenAuthenticatable.setup do |config| 159 | config.should_ensure_authentication_token = true 160 | end 161 | end 162 | 163 | after :each do 164 | Devise::TokenAuthenticatable.setup do |config| 165 | config.should_ensure_authentication_token = false 166 | end 167 | end 168 | 169 | it "sets the authentication token" do 170 | expect(entity).to receive(:ensure_authentication_token).once 171 | 172 | entity.update_attributes(created_at: Time.now) 173 | end 174 | end 175 | 176 | context "when the authentication token should not be ensured" do 177 | it "does not set the authentication token" do 178 | expect(entity).to_not receive(:ensure_authentication_token) 179 | 180 | entity.update_attributes(created_at: Time.now) 181 | end 182 | end 183 | end 184 | end 185 | 186 | describe User do 187 | it_behaves_like "token authenticatable" 188 | end 189 | -------------------------------------------------------------------------------- /spec/requests/devise/token_authenticatable/strategy_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe Devise::Strategies::TokenAuthenticatable do 4 | context "with valid authentication token key and value" do 5 | context "through params" do 6 | it "should be a success" do 7 | swap Devise::TokenAuthenticatable, token_authentication_key: :secret_token do 8 | sign_in_as_new_user_with_token 9 | 10 | expect(response).to be_success 11 | end 12 | end 13 | 14 | it "should set the auth_token parameter" do 15 | swap Devise::TokenAuthenticatable, token_authentication_key: :secret_token do 16 | user = sign_in_as_new_user_with_token 17 | 18 | expect(@request.fullpath).to eq("/users?secret_token=#{user.authentication_token}") 19 | end 20 | end 21 | 22 | it "should authenticate user" do 23 | swap Devise::TokenAuthenticatable, token_authentication_key: :secret_token do 24 | sign_in_as_new_user_with_token 25 | 26 | expect(warden).to be_authenticated(:user) 27 | end 28 | end 29 | 30 | context "when params with the same key as scope exist" do 31 | let(:user) { create(:user, :with_authentication_token) } 32 | 33 | it 'should be a success' do 34 | swap Devise::TokenAuthenticatable, token_authentication_key: :secret_token do 35 | post exhibit_user_path(user), Devise::TokenAuthenticatable.token_authentication_key => user.authentication_token, user: { some: "data" } 36 | 37 | expect(response).to be_success 38 | end 39 | end 40 | 41 | it 'should return proper data' do 42 | swap Devise::TokenAuthenticatable, token_authentication_key: :secret_token do 43 | post exhibit_user_path(user), Devise::TokenAuthenticatable.token_authentication_key => user.authentication_token, user: { some: "data" } 44 | 45 | expect(response.body).to eq('User is authenticated') 46 | end 47 | end 48 | 49 | it 'should authenticate user' do 50 | swap Devise::TokenAuthenticatable, token_authentication_key: :secret_token do 51 | post exhibit_user_path(user), Devise::TokenAuthenticatable.token_authentication_key => user.authentication_token, user: { some: "data" } 52 | 53 | expect(warden).to be_authenticated(:user) 54 | end 55 | end 56 | end 57 | 58 | context "when request is stateless" do 59 | it 'should authenticate the user with use of authentication token' do 60 | swap Devise::TokenAuthenticatable, token_authentication_key: :secret_token do 61 | swap Devise, skip_session_storage: [:token_auth] do 62 | sign_in_as_new_user_with_token 63 | expect(warden).to be_authenticated(:user) 64 | end 65 | end 66 | end 67 | 68 | it 'should redirect to the sign in page' do 69 | swap Devise::TokenAuthenticatable, token_authentication_key: :secret_token do 70 | swap Devise, skip_session_storage: [:token_auth] do 71 | sign_in_as_new_user_with_token 72 | 73 | # Try to access a resource that requires authentication 74 | get users_path 75 | expect(response).to redirect_to new_user_session_path 76 | end 77 | end 78 | end 79 | 80 | it 'should not store the session' do 81 | swap Devise::TokenAuthenticatable, token_authentication_key: :secret_token do 82 | swap Devise, skip_session_storage: [:token_auth] do 83 | sign_in_as_new_user_with_token 84 | 85 | # Try to access a resource that requires authentication 86 | get users_path 87 | expect(warden).to_not be_authenticated(:user) 88 | end 89 | end 90 | end 91 | end 92 | 93 | context "when request is stateless and timeoutable" do 94 | context "on sign in" do 95 | it 'should authenticate the user' do 96 | swap Devise::TokenAuthenticatable, token_authentication_key: :secret_token do 97 | swap Devise, skip_session_storage: [:token_auth], timeout_in: (0.1).second do 98 | sign_in_as_new_user_with_token 99 | expect(warden).to be_authenticated(:user) 100 | end 101 | end 102 | end 103 | end 104 | 105 | context "on delayed access" do 106 | it 'should authenticate the user' do 107 | swap Devise::TokenAuthenticatable, token_authentication_key: :secret_token do 108 | swap Devise, skip_session_storage: [:token_auth], timeout_in: (0.1).second do 109 | user = sign_in_as_new_user_with_token 110 | 111 | # Expiring does not work because we are setting the session value when accessing the resource 112 | Timecop.travel(Time.now + (0.3).second) 113 | 114 | sign_in_as_new_user_with_token(user: user) 115 | expect(warden).to be_authenticated(:user) 116 | 117 | Timecop.return 118 | end 119 | end 120 | end 121 | end 122 | end 123 | 124 | context "when not configured" do 125 | it "should redirect to sign in page" do 126 | swap Devise::TokenAuthenticatable, token_authentication_key: :secret_token do 127 | swap Devise, params_authenticatable: [:database] do 128 | sign_in_as_new_user_with_token 129 | 130 | expect(response).to redirect_to new_user_session_path 131 | end 132 | end 133 | end 134 | 135 | it "should not authenticate user" do 136 | swap Devise::TokenAuthenticatable, token_authentication_key: :secret_token do 137 | swap Devise, params_authenticatable: [:database] do 138 | sign_in_as_new_user_with_token 139 | 140 | expect(warden).to_not be_authenticated(:user) 141 | end 142 | end 143 | end 144 | end 145 | end 146 | 147 | context "through http" do 148 | it "should be a success" do 149 | swap Devise::TokenAuthenticatable, token_authentication_key: :secret_token do 150 | swap Devise, http_authenticatable: true do 151 | sign_in_as_new_user_with_token(http_auth: true) 152 | 153 | expect(response).to be_success 154 | end 155 | end 156 | end 157 | 158 | it "should authenticate user" do 159 | swap Devise::TokenAuthenticatable, token_authentication_key: :secret_token do 160 | swap Devise, http_authenticatable: true do 161 | sign_in_as_new_user_with_token(http_auth: true) 162 | 163 | expect(warden).to be_authenticated(:user) 164 | end 165 | end 166 | end 167 | 168 | context "when not configured" do 169 | it "should be an unauthorized" do 170 | swap Devise::TokenAuthenticatable, token_authentication_key: :secret_token do 171 | swap Devise, http_authenticatable: [:database] do 172 | sign_in_as_new_user_with_token(http_auth: true) 173 | 174 | expect(response.status).to eq(401) 175 | end 176 | end 177 | end 178 | 179 | it "should not authenticate user" do 180 | swap Devise::TokenAuthenticatable, token_authentication_key: :secret_token do 181 | swap Devise, http_authenticatable: [:database] do 182 | sign_in_as_new_user_with_token(http_auth: true) 183 | 184 | expect(warden).to_not be_authenticated(:user) 185 | end 186 | end 187 | end 188 | end 189 | end 190 | 191 | context "through http header" do 192 | it "should redirect to root path" do 193 | swap Devise::TokenAuthenticatable, token_authentication_key: :secret_token do 194 | swap Devise, http_authenticatable: true do 195 | sign_in_as_new_user_with_token(token_auth: true) 196 | 197 | expect(response).to be_success 198 | end 199 | end 200 | end 201 | 202 | it "should not set any token options for Devise" do 203 | swap Devise::TokenAuthenticatable, token_authentication_key: :secret_token do 204 | swap Devise, http_authenticatable: true do 205 | sign_in_as_new_user_with_token(token_auth: true) 206 | 207 | expect(request.env['devise.token_options']).to eq({}) 208 | end 209 | end 210 | end 211 | 212 | it "should authenticate user" do 213 | swap Devise::TokenAuthenticatable, token_authentication_key: :secret_token do 214 | swap Devise, http_authenticatable: true do 215 | sign_in_as_new_user_with_token(token_auth: true) 216 | 217 | expect(warden).to be_authenticated(:user) 218 | end 219 | end 220 | end 221 | 222 | context "with options" do 223 | let(:signature) { "**TESTSIGNATURE**" } 224 | 225 | it "should redirect to root path" do 226 | swap Devise::TokenAuthenticatable, token_authentication_key: :secret_token do 227 | swap Devise, http_authenticatable: [:token] do 228 | sign_in_as_new_user_with_token(token_auth: true, token_options: { signature: signature, nonce: 'def' }) 229 | 230 | expect(response).to be_success 231 | end 232 | end 233 | end 234 | 235 | it "should set the signature option" do 236 | swap Devise::TokenAuthenticatable, token_authentication_key: :secret_token do 237 | swap Devise, http_authenticatable: [:token] do 238 | sign_in_as_new_user_with_token(token_auth: true, token_options: { signature: signature, nonce: 'def' }) 239 | 240 | expect(request.env['devise.token_options'][:signature]).to eq(signature) 241 | end 242 | end 243 | end 244 | 245 | it "should set the nonce option" do 246 | swap Devise::TokenAuthenticatable, token_authentication_key: :secret_token do 247 | swap Devise, http_authenticatable: [:token] do 248 | sign_in_as_new_user_with_token(token_auth: true, token_options: { signature: signature, nonce: 'def' }) 249 | 250 | expect(request.env['devise.token_options'][:nonce]).to eq('def') 251 | end 252 | end 253 | end 254 | 255 | it "should authenticate user" do 256 | swap Devise::TokenAuthenticatable, token_authentication_key: :secret_token do 257 | swap Devise, http_authenticatable: [:token] do 258 | sign_in_as_new_user_with_token(token_auth: true, token_options: { signature: signature, nonce: 'def' }) 259 | 260 | expect(warden).to be_authenticated(:user) 261 | end 262 | end 263 | end 264 | end 265 | 266 | context "with denied token authorization" do 267 | it "should be an unauthorized" do 268 | swap Devise::TokenAuthenticatable, token_authentication_key: :secret_token do 269 | swap Devise, http_authenticatable: false do 270 | sign_in_as_new_user_with_token(token_auth: true) 271 | 272 | expect(response.status).to eq(401) 273 | end 274 | end 275 | end 276 | 277 | it "should not authenticate user" do 278 | swap Devise::TokenAuthenticatable, token_authentication_key: :secret_token do 279 | swap Devise, http_authenticatable: false do 280 | sign_in_as_new_user_with_token(token_auth: true) 281 | 282 | expect(warden).to_not be_authenticated(:user) 283 | end 284 | end 285 | end 286 | end 287 | end 288 | end 289 | 290 | context "with improper authentication token key" do 291 | it "should redirect to the sign in page" do 292 | swap Devise::TokenAuthenticatable, token_authentication_key: :donald_duck_token do 293 | sign_in_as_new_user_with_token(auth_token_key: :secret_token) 294 | 295 | expect(response).to redirect_to new_user_session_path 296 | end 297 | end 298 | 299 | it "should not authenticate user" do 300 | swap Devise::TokenAuthenticatable, token_authentication_key: :donald_duck_token do 301 | sign_in_as_new_user_with_token(auth_token_key: :secret_token) 302 | 303 | expect(warden).to_not be_authenticated(:user) 304 | end 305 | end 306 | 307 | it "should not be subject to injection" do 308 | swap Devise::TokenAuthenticatable, token_authentication_key: :secret_token do 309 | user1 = create(:user, :with_authentication_token) 310 | create(:user, :with_authentication_token) 311 | 312 | get users_path(Devise::TokenAuthenticatable.token_authentication_key.to_s + '[$ne]' => user1.authentication_token) 313 | expect(warden).to_not be_authenticated(:user) 314 | end 315 | end 316 | end 317 | 318 | context "with improper authentication token value" do 319 | context "through params" do 320 | before { sign_in_as_new_user_with_token(auth_token: '*** INVALID TOKEN ***') } 321 | 322 | it "should redirect to the sign in page" do 323 | expect(response).to redirect_to new_user_session_path 324 | end 325 | 326 | it "should not authenticate user" do 327 | expect(warden).to_not be_authenticated(:user) 328 | end 329 | end 330 | 331 | context "through http header" do 332 | before { sign_in_as_new_user_with_token(token_auth: true, auth_token: '*** INVALID TOKEN ***') } 333 | 334 | it "should be an unauthorized" do 335 | expect(response.status).to eq(401) 336 | end 337 | 338 | it "does not authenticate with improper authentication token value in header" do 339 | expect(warden).to_not be_authenticated(:user) 340 | end 341 | end 342 | end 343 | 344 | context "with expired authentication token value" do 345 | context "through params" do 346 | it "should redirect to the sign in page" do 347 | swap Devise::TokenAuthenticatable, token_expires_in: 1.hour do 348 | sign_in_as_new_user_with_token(use: :with_day_old_token) 349 | 350 | expect(response).to redirect_to new_user_session_path 351 | end 352 | end 353 | 354 | it "should not authenticate user" do 355 | swap Devise::TokenAuthenticatable, token_expires_in: 1.hour do 356 | sign_in_as_new_user_with_token(use: :with_day_old_token) 357 | 358 | expect(warden).to_not be_authenticated(:user) 359 | end 360 | end 361 | 362 | context "through http header" do 363 | it "should redirect to the sign in page" do 364 | swap Devise::TokenAuthenticatable, token_expires_in: 1.hour do 365 | swap Devise, http_authenticatable: true do 366 | sign_in_as_new_user_with_token(http_auth: true, use: :with_day_old_token) 367 | 368 | expect(response.status).to eq(401) 369 | end 370 | end 371 | end 372 | 373 | it "does not authenticate with expired authentication token value in header" do 374 | swap Devise::TokenAuthenticatable, token_expires_in: 1.hour do 375 | swap Devise, http_authenticatable: true do 376 | sign_in_as_new_user_with_token(http_auth: true, use: :with_day_old_token) 377 | 378 | expect(warden).to_not be_authenticated(:user) 379 | end 380 | end 381 | end 382 | end 383 | end 384 | end 385 | end 386 | -------------------------------------------------------------------------------- /spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | ENV["RAILS_ENV"] ||= 'test' 2 | 3 | # Required modules 4 | require 'rails/all' 5 | require 'devise' 6 | require 'devise/token_authenticatable' 7 | require 'rspec/rails' 8 | require 'timecop' 9 | require 'pry' 10 | 11 | # Required spec helper files 12 | require 'support/rails_app/config/environment' 13 | require 'support/helpers' 14 | require 'support/integration' 15 | require 'support/session_helper' 16 | 17 | # factory_girl_rails has to be required after the test rails app 18 | # as it sets the right application root path 19 | require 'factory_girl_rails' 20 | 21 | # Do not show migration output 22 | ActiveRecord::Migration.verbose = false 23 | 24 | # RSpec configuration 25 | # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration 26 | RSpec.configure do |config| 27 | config.use_transactional_fixtures = true 28 | config.run_all_when_everything_filtered = true 29 | 30 | config.include FactoryGirl::Syntax::Methods 31 | 32 | config.infer_spec_type_from_file_location! 33 | 34 | config.before(:suite) do 35 | # Do initial migration 36 | ActiveRecord::Migrator.migrate(File.expand_path("support/rails_app/db/migrate/", File.dirname(__FILE__))) 37 | end 38 | end 39 | -------------------------------------------------------------------------------- /spec/support/helpers.rb: -------------------------------------------------------------------------------- 1 | # Helpers used for devise testing. 2 | # 3 | 4 | # Execute the block setting the given values in 5 | # +new_values+ and restoring the old values 6 | # after the block was executed. 7 | # 8 | def swap(object, new_values) 9 | old_values = {} 10 | 11 | new_values.each do |key, value| 12 | old_values[key] = object.send key 13 | object.send(:"#{key}=", value) 14 | end 15 | 16 | clear_cached_variables(new_values) 17 | 18 | yield 19 | ensure 20 | clear_cached_variables(new_values) 21 | 22 | old_values.each do |key, value| 23 | object.send(:"#{key}=", value) 24 | end 25 | end 26 | 27 | def clear_cached_variables(options) 28 | if options.key?(:case_insensitive_keys) || options.key?(:strip_whitespace_keys) 29 | Devise.mappings.each do |_, mapping| 30 | mapping.to.instance_variable_set(:@devise_parameter_filter, nil) 31 | end 32 | end 33 | end 34 | -------------------------------------------------------------------------------- /spec/support/integration.rb: -------------------------------------------------------------------------------- 1 | # Helpers used in integration testing. 2 | # 3 | 4 | # Shortcut to the warden instance. 5 | # 6 | def warden 7 | request.env['warden'] 8 | end 9 | -------------------------------------------------------------------------------- /spec/support/rails_app/Rakefile: -------------------------------------------------------------------------------- 1 | # Add your own tasks in files placed in lib/tasks ending in .rake, 2 | # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake. 3 | 4 | require File.expand_path('../config/application', __FILE__) 5 | 6 | Rails.application.load_tasks 7 | -------------------------------------------------------------------------------- /spec/support/rails_app/app/controllers/admins/sessions_controller.rb: -------------------------------------------------------------------------------- 1 | class Admins::SessionsController < Devise::SessionsController 2 | def new 3 | flash[:special] = "Welcome to #{controller_path.inspect} controller!" 4 | super 5 | end 6 | end -------------------------------------------------------------------------------- /spec/support/rails_app/app/controllers/admins_controller.rb: -------------------------------------------------------------------------------- 1 | class AdminsController < ApplicationController 2 | before_filter :authenticate_admin! 3 | 4 | def index 5 | end 6 | 7 | def expire 8 | admin_session['last_request_at'] = 31.minutes.ago.utc 9 | render text: 'Admin will be expired on next request' 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /spec/support/rails_app/app/controllers/application_controller.rb: -------------------------------------------------------------------------------- 1 | # Filters added to this controller apply to all controllers in the application. 2 | # Likewise, all the methods added will be available for all controllers. 3 | 4 | class ApplicationController < ActionController::Base 5 | protect_from_forgery 6 | before_filter :current_user, unless: :devise_controller? 7 | before_filter :authenticate_user!, if: :devise_controller? 8 | respond_to *Mime::SET.map(&:to_sym) 9 | end 10 | -------------------------------------------------------------------------------- /spec/support/rails_app/app/controllers/home_controller.rb: -------------------------------------------------------------------------------- 1 | class HomeController < ApplicationController 2 | def index 3 | end 4 | 5 | def private 6 | end 7 | 8 | def user_dashboard 9 | end 10 | 11 | def admin_dashboard 12 | end 13 | 14 | def join 15 | end 16 | 17 | def set 18 | session["devise.foo_bar"] = "something" 19 | head :ok 20 | end 21 | 22 | def unauthenticated 23 | render text: "unauthenticated", status: :unauthorized 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /spec/support/rails_app/app/controllers/publisher/registrations_controller.rb: -------------------------------------------------------------------------------- 1 | class Publisher::RegistrationsController < ApplicationController 2 | end -------------------------------------------------------------------------------- /spec/support/rails_app/app/controllers/publisher/sessions_controller.rb: -------------------------------------------------------------------------------- 1 | class Publisher::SessionsController < ApplicationController 2 | end -------------------------------------------------------------------------------- /spec/support/rails_app/app/controllers/users_controller.rb: -------------------------------------------------------------------------------- 1 | class UsersController < ApplicationController 2 | prepend_before_filter :current_user, only: :exhibit 3 | before_filter :authenticate_user!, except: [:accept, :exhibit] 4 | 5 | respond_to :html, :xml 6 | 7 | def index 8 | user_session[:cart] = "Cart" 9 | respond_with(current_user) 10 | end 11 | 12 | def edit_form 13 | user_session['last_request_at'] = 31.minutes.ago.utc 14 | end 15 | 16 | def update_form 17 | render text: 'Update' 18 | end 19 | 20 | def accept 21 | @current_user = current_user 22 | end 23 | 24 | def exhibit 25 | render text: current_user ? "User is authenticated" : "User is not authenticated" 26 | end 27 | 28 | def expire 29 | user_session['last_request_at'] = 31.minutes.ago.utc 30 | render text: 'User will be expired on next request' 31 | end 32 | end 33 | -------------------------------------------------------------------------------- /spec/support/rails_app/app/mailers/users/mailer.rb: -------------------------------------------------------------------------------- 1 | class Users::Mailer < Devise::Mailer 2 | default from: 'custom@example.com' 3 | end 4 | 5 | class Users::ReplyToMailer < Devise::Mailer 6 | default from: 'custom@example.com' 7 | default reply_to: 'custom_reply_to@example.com' 8 | end 9 | 10 | class Users::FromProcMailer < Devise::Mailer 11 | default from: proc { 'custom@example.com' } 12 | end 13 | -------------------------------------------------------------------------------- /spec/support/rails_app/app/models/admin.rb: -------------------------------------------------------------------------------- 1 | class Admin < ActiveRecord::Base 2 | devise :database_authenticatable, :registerable, 3 | :timeoutable, :recoverable, :lockable, :confirmable, 4 | unlock_strategy: :time, lock_strategy: :none, 5 | allow_unconfirmed_access_for: 2.weeks, reconfirmable: true 6 | 7 | validates_length_of :reset_password_token, minimum: 3, allow_blank: true 8 | validates_uniqueness_of :email, allow_blank: true, if: :email_changed? 9 | end 10 | -------------------------------------------------------------------------------- /spec/support/rails_app/app/models/user.rb: -------------------------------------------------------------------------------- 1 | class User < ActiveRecord::Base 2 | devise :database_authenticatable, :confirmable, :lockable, :recoverable, 3 | :registerable, :rememberable, :timeoutable, :token_authenticatable, 4 | :trackable, :validatable, reconfirmable: false 5 | 6 | attr_accessor :other_key 7 | 8 | def raw_confirmation_token 9 | @raw_confirmation_token 10 | end 11 | 12 | module ExtendMethods 13 | def new_with_session(params, session) 14 | super.tap do |user| 15 | if data = session["devise.facebook_data"] 16 | user.email = data["email"] 17 | user.confirmed_at = Time.now 18 | end 19 | end 20 | end 21 | end 22 | 23 | # They need to be included after Devise is called. 24 | extend ExtendMethods 25 | end 26 | -------------------------------------------------------------------------------- /spec/support/rails_app/app/views/users/index.html.erb: -------------------------------------------------------------------------------- 1 | Welcome User #<%= current_user.id %>! 2 | -------------------------------------------------------------------------------- /spec/support/rails_app/config.ru: -------------------------------------------------------------------------------- 1 | # This file is used by Rack-based servers to start the application. 2 | 3 | require ::File.expand_path('../config/environment', __FILE__) 4 | run RailsApp::Application 5 | -------------------------------------------------------------------------------- /spec/support/rails_app/config/application.rb: -------------------------------------------------------------------------------- 1 | require File.expand_path('../boot', __FILE__) 2 | 3 | module Devise 4 | module TokenAuthenticatable 5 | class RailsApp < Rails::Application 6 | config.active_support.deprecation = :log 7 | config.action_mailer.default_url_options = { host: "localhost", port: 3000 } 8 | config.action_mailer.delivery_method = :test 9 | config.i18n.enforce_available_locales = false 10 | config.eager_load = false 11 | end 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /spec/support/rails_app/config/boot.rb: -------------------------------------------------------------------------------- 1 | # Set up gems listed in the Gemfile. 2 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../../../Gemfile', __FILE__) 3 | require 'bundler/setup' if File.exists?(ENV['BUNDLE_GEMFILE']) 4 | -------------------------------------------------------------------------------- /spec/support/rails_app/config/database.yml: -------------------------------------------------------------------------------- 1 | # SQLite version 3.x 2 | # gem install sqlite3-ruby (not necessary on OS X Leopard) 3 | development: 4 | adapter: sqlite3 5 | database: db/development.sqlite3 6 | pool: 5 7 | timeout: 5000 8 | 9 | test: 10 | adapter: sqlite3 11 | database: ":memory:" 12 | -------------------------------------------------------------------------------- /spec/support/rails_app/config/environment.rb: -------------------------------------------------------------------------------- 1 | # Load the rails application. 2 | require File.expand_path('../application', __FILE__) 3 | 4 | # Initialize the rails application. 5 | Devise::TokenAuthenticatable::RailsApp.initialize! 6 | -------------------------------------------------------------------------------- /spec/support/rails_app/config/initializers/backtrace_silencers.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces. 4 | # Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ } 5 | 6 | # You can also remove all the silencers if you're trying to debug a problem that might stem from framework code. 7 | Rails.backtrace_cleaner.remove_silencers! 8 | -------------------------------------------------------------------------------- /spec/support/rails_app/config/initializers/devise.rb: -------------------------------------------------------------------------------- 1 | # Use this hook to configure devise mailer, warden hooks and so forth. The first 2 | # four configuration values can also be set straight in your models. 3 | Devise.setup do |config| 4 | config.secret_key = "d9eb5171c59a4c817f68b0de27b8c1e340c2341b52cdbc60d3083d4e8958532" \ 5 | "18dcc5f589cafde048faec956b61f864b9b5513ff9ce29bf9e5d58b0f234f8e3b" 6 | 7 | # ==> Mailer Configuration 8 | # Configure the e-mail address which will be shown in Devise::Mailer, 9 | # note that it will be overwritten if you use your own mailer class with default "from" parameter. 10 | config.mailer_sender = "please-change-me@config-initializers-devise.com" 11 | 12 | # Configure the class responsible to send e-mails. 13 | # config.mailer = "Devise::Mailer" 14 | 15 | # ==> ORM configuration 16 | # Load and configure the ORM. Supports :active_record (default) and 17 | # :mongoid (bson_ext recommended) by default. Other ORMs may be 18 | # available as additional gems. 19 | require "devise/orm/active_record" 20 | 21 | # ==> Configuration for any authentication mechanism 22 | # Configure which keys are used when authenticating a user. By default is 23 | # just :email. You can configure it to use [:username, :subdomain], so for 24 | # authenticating a user, both parameters are required. Remember that those 25 | # parameters are used only when authenticating and not when retrieving from 26 | # session. If you need permissions, you should implement that in a before filter. 27 | # You can also supply hash where the value is a boolean expliciting if authentication 28 | # should be aborted or not if the value is not present. By default is empty. 29 | # config.authentication_keys = [ :email ] 30 | 31 | # Configure parameters from the request object used for authentication. Each entry 32 | # given should be a request method and it will automatically be passed to 33 | # find_for_authentication method and considered in your model lookup. For instance, 34 | # if you set :request_keys to [:subdomain], :subdomain will be used on authentication. 35 | # The same considerations mentioned for authentication_keys also apply to request_keys. 36 | # config.request_keys = [] 37 | 38 | # Configure which authentication keys should be case-insensitive. 39 | # These keys will be downcased upon creating or modifying a user and when used 40 | # to authenticate or find a user. Default is :email. 41 | config.case_insensitive_keys = [ :email ] 42 | 43 | # Configure which authentication keys should have whitespace stripped. 44 | # These keys will have whitespace before and after removed upon creating or 45 | # modifying a user and when used to authenticate or find a user. Default is :email. 46 | config.strip_whitespace_keys = [ :email ] 47 | 48 | # Tell if authentication through request.params is enabled. True by default. 49 | # config.params_authenticatable = true 50 | 51 | # Tell if authentication through HTTP Auth is enabled. False by default. 52 | # It can be set to an array that will enable http authentication only for the 53 | # given strategies, for example, `config.http_authenticatable = [:database]` will 54 | # enable it only for database authentication. The supported strategies are: 55 | # :database = Support basic authentication with authentication key + password 56 | # :token = Support token authentication 57 | config.http_authenticatable = true 58 | 59 | # If http headers should be returned for AJAX requests. True by default. 60 | # config.http_authenticatable_on_xhr = true 61 | 62 | # The realm used in Http Basic Authentication. "Application" by default. 63 | # config.http_authentication_realm = "Application" 64 | 65 | # ==> Configuration for :database_authenticatable 66 | # For bcrypt, this is the cost for hashing the password and defaults to 10. If 67 | # using other encryptors, it sets how many times you want the password re-encrypted. 68 | config.stretches = Rails.env.test? ? 1 : 10 69 | 70 | # ==> Configuration for :confirmable 71 | # The time you want to give your user to confirm his account. During this time 72 | # he will be able to access your application without confirming. Default is nil. 73 | # When allow_unconfirmed_access_for is zero, the user won't be able to sign in without confirming. 74 | # You can use this to let your user access some features of your application 75 | # without confirming the account, but blocking it after a certain period 76 | # (ie 2 days). 77 | # config.allow_unconfirmed_access_for = 2.days 78 | 79 | # Defines which key will be used when confirming an account 80 | # config.confirmation_keys = [ :email ] 81 | 82 | # ==> Configuration for :rememberable 83 | # The time the user will be remembered without asking for credentials again. 84 | # config.remember_for = 2.weeks 85 | 86 | # If true, a valid remember token can be re-used between multiple browsers. 87 | # config.remember_across_browsers = true 88 | 89 | # If true, extends the user's remember period when remembered via cookie. 90 | # config.extend_remember_period = false 91 | 92 | # ==> Configuration for :validatable 93 | # Range for password length. Default is 8..128. 94 | # config.password_length = 8..128 95 | 96 | # Regex to use to validate the email address 97 | # config.email_regexp = /^([\w\.%\+\-]+)@([\w\-]+\.)+([\w]{2,})$/i 98 | 99 | # ==> Configuration for :timeoutable 100 | # The time you want to timeout the user session without activity. After this 101 | # time the user will be asked for credentials again. Default is 30 minutes. 102 | # config.timeout_in = 30.minutes 103 | 104 | # ==> Configuration for :lockable 105 | # Defines which strategy will be used to lock an account. 106 | # :failed_attempts = Locks an account after a number of failed attempts to sign in. 107 | # :none = No lock strategy. You should handle locking by yourself. 108 | # config.lock_strategy = :failed_attempts 109 | 110 | # Defines which key will be used when locking and unlocking an account 111 | # config.unlock_keys = [ :email ] 112 | 113 | # Defines which strategy will be used to unlock an account. 114 | # :email = Sends an unlock link to the user email 115 | # :time = Re-enables login after a certain amount of time (see :unlock_in below) 116 | # :both = Enables both strategies 117 | # :none = No unlock strategy. You should handle unlocking by yourself. 118 | # config.unlock_strategy = :both 119 | 120 | # Number of authentication tries before locking an account if lock_strategy 121 | # is failed attempts. 122 | # config.maximum_attempts = 20 123 | 124 | # Time interval to unlock the account if :time is enabled as unlock_strategy. 125 | # config.unlock_in = 1.hour 126 | 127 | # ==> Configuration for :recoverable 128 | # 129 | # Defines which key will be used when recovering the password for an account 130 | # config.reset_password_keys = [ :email ] 131 | 132 | # Time interval you can reset your password with a reset password key. 133 | # Don't put a too small interval or your users won't have the time to 134 | # change their passwords. 135 | config.reset_password_within = 2.hours 136 | 137 | # Setup a pepper to generate the encrypted password. 138 | config.pepper = "d142367154e5beacca404b1a6a4f8bc52c6fdcfa3ccc3cf8eb49f3458a688ee6ac3b9fae488432a3bfca863b8a90008368a9f3a3dfbe5a962e64b6ab8f3a3a1a" 139 | 140 | # ==> Configuration for :token_authenticatable 141 | # Defines name of the authentication token params key 142 | # config.token_authentication_key = :auth_token 143 | 144 | # ==> Scopes configuration 145 | # Turn scoped views on. Before rendering "sessions/new", it will first check for 146 | # "users/sessions/new". It's turned off by default because it's slower if you 147 | # are using only default views. 148 | # config.scoped_views = false 149 | 150 | # Configure the default scope given to Warden. By default it's the first 151 | # devise role declared in your routes (usually :user). 152 | # config.default_scope = :user 153 | 154 | # Configure sign_out behavior. 155 | # Sign_out action can be scoped (i.e. /users/sign_out affects only :user scope). 156 | # The default is true, which means any logout action will sign out all active scopes. 157 | # config.sign_out_all_scopes = true 158 | 159 | # ==> Navigation configuration 160 | # Lists the formats that should be treated as navigational. Formats like 161 | # :html, should redirect to the sign in page when the user does not have 162 | # access, but formats like :xml or :json, should return 401. 163 | # If you have any extra navigational formats, like :iphone or :mobile, you 164 | # should add them to the navigational formats lists. Default is [:html] 165 | # config.navigational_formats = [:html, :iphone] 166 | 167 | # The default HTTP method used to sign out a resource. Default is :get. 168 | # config.sign_out_via = :get 169 | 170 | # ==> Warden configuration 171 | # If you want to use other strategies, that are not supported by Devise, or 172 | # change the failure app, you can configure them inside the config.warden block. 173 | # 174 | # config.warden do |manager| 175 | # manager.failure_app = AnotherApp 176 | # manager.default_strategies(:scope => :user).unshift :some_external_strategy 177 | # end 178 | end 179 | -------------------------------------------------------------------------------- /spec/support/rails_app/config/initializers/inflections.rb: -------------------------------------------------------------------------------- 1 | ActiveSupport::Inflector.inflections do |inflect| 2 | end 3 | -------------------------------------------------------------------------------- /spec/support/rails_app/config/initializers/secret_token.rb: -------------------------------------------------------------------------------- 1 | config = Rails.application.config 2 | 3 | if Rails.version.start_with? '4' 4 | config.secret_key_base = 'd588e99efff13a86461fd6ab82327823ad2f8feb5dc217ce652cdd9f0dfc5eb4b5a62a92d24d2574d7d51dfb1ea8dd453ea54e00cf672159a13104a135422a10' 5 | else 6 | config.secret_token = 'ea942c41850d502f2c8283e26bdc57829f471bb18224ddff0a192c4f32cdf6cb5aa0d82b3a7a7adbeb640c4b06f3aa1cd5f098162d8240f669b39d6b49680571' 7 | end 8 | -------------------------------------------------------------------------------- /spec/support/rails_app/config/initializers/session_store.rb: -------------------------------------------------------------------------------- 1 | Devise::TokenAuthenticatable::RailsApp.config.session_store :cookie_store, key: '_my_app' 2 | -------------------------------------------------------------------------------- /spec/support/rails_app/config/routes.rb: -------------------------------------------------------------------------------- 1 | Rails.application.routes.draw do 2 | # Resources for testing 3 | resources :users, only: [:index] do 4 | member do 5 | get :expire 6 | get :accept 7 | get :edit_form 8 | put :update_form 9 | end 10 | 11 | authenticate do 12 | post :exhibit, on: :member 13 | end 14 | end 15 | 16 | resources :admins, only: [:index] do 17 | get :expire, on: :member 18 | end 19 | 20 | # Users scope 21 | devise_for :users 22 | 23 | as :user do 24 | get "/as/sign_in", to: "devise/sessions#new" 25 | end 26 | 27 | get "/sign_in", to: "devise/sessions#new" 28 | 29 | # Admin scope 30 | devise_for :admin, path: "admin_area", controllers: { sessions: "admins/sessions" }, skip: :passwords 31 | 32 | get "/admin_area/home", to: "admins#index", as: :admin_root 33 | get "/anywhere", to: "foo#bar", as: :new_admin_password 34 | 35 | authenticate(:admin) do 36 | get "/private", to: "home#private", as: :private 37 | end 38 | 39 | authenticate(:admin, lambda { |admin| admin.active? }) do 40 | get "/private/active", to: "home#private", as: :private_active 41 | end 42 | 43 | authenticated :admin do 44 | get "/dashboard", to: "home#admin_dashboard" 45 | end 46 | 47 | authenticated :admin, lambda { |admin| admin.active? } do 48 | get "/dashboard/active", to: "home#admin_dashboard" 49 | end 50 | 51 | authenticated do 52 | get "/dashboard", to: "home#user_dashboard" 53 | end 54 | 55 | unauthenticated do 56 | get "/join", to: "home#join" 57 | end 58 | 59 | # Routes for constraints testing 60 | devise_for :headquarters_admin, class_name: "Admin", path: "headquarters", constraints: { host: /192\.168\.1\.\d\d\d/ } 61 | 62 | constraints(host: /192\.168\.1\.\d\d\d/) do 63 | devise_for :homebase_admin, class_name: "Admin", path: "homebase" 64 | end 65 | 66 | devise_for :skip_admin, class_name: "Admin", skip: :all 67 | 68 | # Routes for format=false testing 69 | devise_for :htmlonly_admin, class_name: "Admin", 70 | skip: [:confirmations, :unlocks], 71 | path: "htmlonly_admin", 72 | format: false, 73 | skip_helpers: [:confirmations, :unlocks] 74 | 75 | devise_for :htmlonly_users, class_name: "User", 76 | only: [:confirmations, :unlocks], 77 | path: "htmlonly_users", 78 | format: false, 79 | skip_helpers: true 80 | 81 | # Other routes for routing_test.rb 82 | devise_for :reader, class_name: "User", only: :passwords 83 | 84 | scope host: "sub.example.com" do 85 | devise_for :sub_admin, class_name: "Admin" 86 | end 87 | 88 | namespace :publisher, path_names: { sign_in: "i_dont_care", sign_out: "get_out" } do 89 | devise_for :accounts, class_name: "Admin", path_names: { sign_in: "get_in" } 90 | end 91 | 92 | scope ":locale", module: :invalid do 93 | devise_for :accounts, singular: "manager", class_name: "Admin", 94 | path_names: { 95 | sign_in: "login", 96 | sign_out: "logout", 97 | password: "secret", 98 | confirmation: "verification", 99 | unlock: "unblock", 100 | sign_up: "register", 101 | registration: "management", 102 | cancel: "giveup" 103 | }, failure_app: lambda { |env| [404, { "Content-Type" => "text/plain" }, ["Oops, not found"]] }, 104 | module: :devise 105 | end 106 | 107 | namespace :sign_out_via, module: "devise" do 108 | devise_for :deletes, sign_out_via: :delete, class_name: "Admin" 109 | devise_for :posts, sign_out_via: :post, class_name: "Admin" 110 | devise_for :delete_or_posts, sign_out_via: [:delete, :post], class_name: "Admin" 111 | end 112 | 113 | get "/set", to: "home#set" 114 | get "/unauthenticated", to: "home#unauthenticated" 115 | get "/custom_strategy/new" 116 | 117 | root to: "home#index", via: [:get, :post] 118 | end 119 | -------------------------------------------------------------------------------- /spec/support/rails_app/db/migrate/20100401102949_create_tables.rb: -------------------------------------------------------------------------------- 1 | class CreateTables < ActiveRecord::Migration 2 | def self.up 3 | create_table :users do |t| 4 | t.string :username 5 | t.string :facebook_token 6 | 7 | ## Database authenticatable 8 | t.string :email, null: false, default: "" 9 | t.string :encrypted_password, null: false, default: "" 10 | 11 | ## Recoverable 12 | t.string :reset_password_token 13 | t.datetime :reset_password_sent_at 14 | 15 | ## Rememberable 16 | t.datetime :remember_created_at 17 | 18 | ## Trackable 19 | t.integer :sign_in_count, default: 0 20 | t.datetime :current_sign_in_at 21 | t.datetime :last_sign_in_at 22 | t.string :current_sign_in_ip 23 | t.string :last_sign_in_ip 24 | 25 | ## Confirmable 26 | t.string :confirmation_token 27 | t.datetime :confirmed_at 28 | t.datetime :confirmation_sent_at 29 | # t.string :unconfirmed_email # Only if using reconfirmable 30 | 31 | ## Lockable 32 | t.integer :failed_attempts, default: 0 # Only if lock strategy is :failed_attempts 33 | t.string :unlock_token # Only if unlock strategy is :email or :both 34 | t.datetime :locked_at 35 | 36 | ## Token authenticatable 37 | t.string :authentication_token 38 | t.datetime :authentication_token_created_at, null: true 39 | 40 | t.timestamps 41 | end 42 | 43 | create_table :admins do |t| 44 | ## Database authenticatable 45 | t.string :email, null: true 46 | t.string :encrypted_password, null: true 47 | 48 | ## Recoverable 49 | t.string :reset_password_token 50 | t.datetime :reset_password_sent_at 51 | 52 | ## Rememberable 53 | t.datetime :remember_created_at 54 | 55 | ## Confirmable 56 | t.string :confirmation_token 57 | t.datetime :confirmed_at 58 | t.datetime :confirmation_sent_at 59 | t.string :unconfirmed_email # Only if using reconfirmable 60 | 61 | ## Lockable 62 | t.datetime :locked_at 63 | 64 | ## Attribute for testing route blocks 65 | t.boolean :active, default: false 66 | 67 | t.timestamps 68 | end 69 | end 70 | 71 | def self.down 72 | drop_table :users 73 | drop_table :admins 74 | end 75 | end 76 | -------------------------------------------------------------------------------- /spec/support/rails_app/db/schema.rb: -------------------------------------------------------------------------------- 1 | # This file is auto-generated from the current state of the database. Instead 2 | # of editing this file, please use the migrations feature of Active Record to 3 | # incrementally modify your database, and then regenerate this schema definition. 4 | # 5 | # Note that this schema.rb definition is the authoritative source for your 6 | # database schema. If you need to create the application database on another 7 | # system, you should be using db:schema:load, not running all the migrations 8 | # from scratch. The latter is a flawed and unsustainable approach (the more migrations 9 | # you'll amass, the slower it'll run and the greater likelihood for issues). 10 | # 11 | # It's strongly recommended to check this file into your version control system. 12 | 13 | ActiveRecord::Schema.define(:version => 20100401102949) do 14 | 15 | create_table "admins", :force => true do |t| 16 | t.string "email" 17 | t.string "encrypted_password", :limit => 128 18 | t.string "password_salt" 19 | t.string "remember_token" 20 | t.datetime "remember_created_at" 21 | t.string "reset_password_token" 22 | t.integer "failed_attempts", :default => 0 23 | t.string "unlock_token" 24 | t.datetime "locked_at" 25 | t.datetime "created_at" 26 | t.datetime "updated_at" 27 | end 28 | 29 | create_table "users", :force => true do |t| 30 | t.string "username" 31 | t.string "facebook_token" 32 | t.string "email", :default => "", :null => false 33 | t.string "encrypted_password", :limit => 128, :default => "", :null => false 34 | t.string "confirmation_token" 35 | t.datetime "confirmed_at" 36 | t.datetime "confirmation_sent_at" 37 | t.string "reset_password_token" 38 | t.datetime "remember_created_at" 39 | t.integer "sign_in_count", :default => 0 40 | t.datetime "current_sign_in_at" 41 | t.datetime "last_sign_in_at" 42 | t.string "current_sign_in_ip" 43 | t.string "last_sign_in_ip" 44 | t.integer "failed_attempts", :default => 0 45 | t.string "unlock_token" 46 | t.datetime "locked_at" 47 | t.string "authentication_token" 48 | t.datetime "authentication_token_created_at" 49 | t.datetime "created_at" 50 | t.datetime "updated_at" 51 | end 52 | 53 | end 54 | -------------------------------------------------------------------------------- /spec/support/rails_app/public/404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | The page you were looking for doesn't exist (404) 5 | 17 | 18 | 19 | 20 | 21 |
22 |

The page you were looking for doesn't exist.

23 |

You may have mistyped the address or the page may have moved.

24 |
25 | 26 | 27 | -------------------------------------------------------------------------------- /spec/support/rails_app/public/422.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | The change you wanted was rejected (422) 5 | 17 | 18 | 19 | 20 | 21 |
22 |

The change you wanted was rejected.

23 |

Maybe you tried to change something you didn't have access to.

24 |
25 | 26 | 27 | -------------------------------------------------------------------------------- /spec/support/rails_app/public/500.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | We're sorry, but something went wrong (500) 5 | 17 | 18 | 19 | 20 | 21 |
22 |

We're sorry, but something went wrong.

23 |

We've been notified about this issue and we'll take a look at it shortly.

24 |
25 | 26 | 27 | -------------------------------------------------------------------------------- /spec/support/rails_app/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baschtl/devise-token_authenticatable/2e9e3e9ed59916715a019ae3fd9399bba9c1b3e6/spec/support/rails_app/public/favicon.ico -------------------------------------------------------------------------------- /spec/support/session_helper.rb: -------------------------------------------------------------------------------- 1 | # Helper methods for user sign in with 2 | # authentication token. 3 | # 4 | 5 | # Signs in a user via different methods (i.e., HTTP AUTH, 6 | # Token Auth, plain). If no user is given with the +options+ 7 | # a new one is created. 8 | # 9 | def sign_in_as_new_user_with_token(options = {}) 10 | trait = options[:use] ? options[:use] : :with_authentication_token 11 | user = options.delete(:user) || create(:user, trait) 12 | 13 | options[:auth_token_key] ||= Devise::TokenAuthenticatable.token_authentication_key 14 | options[:auth_token] ||= user.authentication_token 15 | 16 | if options[:http_auth] 17 | header = "Basic #{Base64.encode64("#{options[:auth_token]}:X")}" 18 | get users_path(format: :xml), {}, "HTTP_AUTHORIZATION" => header 19 | elsif options[:token_auth] 20 | token_options = options[:token_options] || {} 21 | header = ActionController::HttpAuthentication::Token.encode_credentials(options[:auth_token], token_options) 22 | get users_path(format: :xml), {}, "HTTP_AUTHORIZATION" => header 23 | else 24 | get users_path(options[:auth_token_key].to_sym => options[:auth_token]) 25 | end 26 | 27 | user 28 | end 29 | -------------------------------------------------------------------------------- /spec/token_authenticatable_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe Devise::TokenAuthenticatable do 4 | context "configuring the token_expires_in" do 5 | let(:expire_time) { 1.hour } 6 | 7 | it "should set the configuration" do 8 | expect { 9 | Devise::TokenAuthenticatable.setup do |config| 10 | config.token_expires_in = expire_time 11 | end 12 | }.to change { Devise::TokenAuthenticatable.token_expires_in }.from(nil).to(expire_time) 13 | end 14 | end 15 | 16 | context "configuring the token_authentication_key" do 17 | let(:new_key) { :other_key } 18 | 19 | it "should set the configuration" do 20 | expect { 21 | Devise::TokenAuthenticatable.setup do |config| 22 | config.token_authentication_key = new_key 23 | end 24 | }.to change { Devise::TokenAuthenticatable.token_authentication_key }.from(:auth_token).to(new_key) 25 | end 26 | end 27 | 28 | context "configuring the should_reset_authentication_token" do 29 | let(:should_reset) { true } 30 | 31 | it "should set the configuration" do 32 | expect { 33 | Devise::TokenAuthenticatable.setup do |config| 34 | config.should_reset_authentication_token = should_reset 35 | end 36 | }.to change { Devise::TokenAuthenticatable.should_reset_authentication_token }.from(false).to(should_reset) 37 | end 38 | end 39 | 40 | context "configuring the should_ensure_authentication_token" do 41 | let(:should_ensure) { true } 42 | 43 | it "should set the configuration" do 44 | expect { 45 | Devise::TokenAuthenticatable.setup do |config| 46 | config.should_ensure_authentication_token = should_ensure 47 | end 48 | }.to change { Devise::TokenAuthenticatable.should_ensure_authentication_token }.from(false).to(should_ensure) 49 | end 50 | end 51 | end 52 | --------------------------------------------------------------------------------