diff --git a/.github_changelog_generator b/.github_changelog_generator new file mode 100644 index 000000000..c57c00448 --- /dev/null +++ b/.github_changelog_generator @@ -0,0 +1,5 @@ +bug-labels=bug,Bug,fix,Fix +enhancement-labels=enhancement,Enhancement,feat,Feat +since-tag=v0.1.42 +unreleased-label=v0.1.43 +base=CHANGELOG.md \ No newline at end of file diff --git a/.gitignore b/.gitignore index 3bda27950..4e2728039 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,7 @@ test/dummy/tmp/ test/dummy/.sass-cache test/dummy/config/application.yml coverage +.idea +.irb_history +.ruby-version +.ruby-gemset diff --git a/.ruby-version b/.ruby-version deleted file mode 100644 index ac2cdeba0..000000000 --- a/.ruby-version +++ /dev/null @@ -1 +0,0 @@ -2.1.3 diff --git a/.travis.yml b/.travis.yml index d15282da9..572f03674 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,19 +1,30 @@ language: ruby cache: bundler +sudo: false rvm: - - 1.9.3 - - 2.1 + - 2.3.1 env: - - DB=sqlite - - DB=mysql - - DB=postgresql + global: + - RAILS_ENV=test + matrix: + - DB=sqlite + - DB=mysql + - DB=postgresql script: - - RAILS_ENV=test bundle exec rake --trace db:migrate - - RAILS_ENV=test CODECLIMATE_REPO_TOKEN=44d7688de8e1b567b4af25ec5083c2cc0a355ab911192a7cbefd1ea25b2ffd3d bundle exec rake + - bundle exec rake --trace db:migrate + - bundle exec rake before_script: - mysql -e 'create database devise_token_auth_test' - psql -c 'create database devise_token_auth_test' -U postgres + +addons: + postgresql: "9.4" + code_climate: + - repo_token: 44d7688de8e1b567b4af25ec5083c2cc0a355ab911192a7cbefd1ea25b2ffd3d + +after_success: + - bundle exec codeclimate-test-reporter diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 000000000..687f76220 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,1374 @@ +# Change Log + +## [v0.1.42](https://github.com/lynndylanhurley/devise_token_auth/tree/v0.1.42) (2017-05-17) +[Full Changelog](https://github.com/lynndylanhurley/devise_token_auth/compare/v0.1.41...v0.1.42) + +**Closed issues:** + +- devise\_token\_auth blocks upgrade to Rails 5.1.0 [\#875](https://github.com/lynndylanhurley/devise_token_auth/issues/875) + +**Merged pull requests:** + +- Support for devise 4.3 that is now supporting rails 5.1 [\#891](https://github.com/lynndylanhurley/devise_token_auth/pull/891) ([silviusimeria](https://github.com/silviusimeria)) + +# Change Log + +## [v0.1.41](https://github.com/lynndylanhurley/devise_token_auth/tree/HEAD) + +[Full Changelog](https://github.com/lynndylanhurley/devise_token_auth/compare/v0.1.40...HEAD) + +**Implemented enhancements:** + +- Rails generator to update views [\#33](https://github.com/lynndylanhurley/devise_token_auth/issues/33) +- Extract Omniauth attributes assignation into a method [\#31](https://github.com/lynndylanhurley/devise_token_auth/issues/31) + +**Fixed bugs:** + +- Generator doesn't work correctly with mongoid and/or rails-api [\#14](https://github.com/lynndylanhurley/devise_token_auth/issues/14) +- Generator issues [\#13](https://github.com/lynndylanhurley/devise_token_auth/issues/13) + +**Closed issues:** + +- Can´t retrieve access token in login response headers [\#877](https://github.com/lynndylanhurley/devise_token_auth/issues/877) +- how do I login a user after account signup? [\#866](https://github.com/lynndylanhurley/devise_token_auth/issues/866) +- Can only register one account. [\#858](https://github.com/lynndylanhurley/devise_token_auth/issues/858) +- No access-token in the header [\#855](https://github.com/lynndylanhurley/devise_token_auth/issues/855) +- Headers not present in all requests [\#851](https://github.com/lynndylanhurley/devise_token_auth/issues/851) +- uninitialized constant SECRET\_KEY\_BASE [\#845](https://github.com/lynndylanhurley/devise_token_auth/issues/845) +- devise\_token\_auth: can't work with Rails subdomain. [\#831](https://github.com/lynndylanhurley/devise_token_auth/issues/831) +- Question: email confirmation token URI with Rails API [\#824](https://github.com/lynndylanhurley/devise_token_auth/issues/824) +- readme code for controller override needs a slight change [\#819](https://github.com/lynndylanhurley/devise_token_auth/issues/819) +- Support for multiple providers during same session [\#815](https://github.com/lynndylanhurley/devise_token_auth/issues/815) +- not supporting for angular1.6 [\#810](https://github.com/lynndylanhurley/devise_token_auth/issues/810) +- Add has one/belongs to assotiation [\#807](https://github.com/lynndylanhurley/devise_token_auth/issues/807) +- redirect\_url required but not permitted in strong parameters [\#805](https://github.com/lynndylanhurley/devise_token_auth/issues/805) +- Data leak on create password reset [\#797](https://github.com/lynndylanhurley/devise_token_auth/issues/797) +- Rails 5 API Mode Not Authorizing [\#796](https://github.com/lynndylanhurley/devise_token_auth/issues/796) +- wrong constant name user [\#784](https://github.com/lynndylanhurley/devise_token_auth/issues/784) +- current\_user returns nill [\#779](https://github.com/lynndylanhurley/devise_token_auth/issues/779) +- ActionController::RoutingError - undefined method `helper\_method' [\#776](https://github.com/lynndylanhurley/devise_token_auth/issues/776) +- Minimum Limits on a token? [\#764](https://github.com/lynndylanhurley/devise_token_auth/issues/764) +- Octopus throwing error when deleting expired tokens [\#761](https://github.com/lynndylanhurley/devise_token_auth/issues/761) +- Only one User model return the correct headers [\#757](https://github.com/lynndylanhurley/devise_token_auth/issues/757) +- ArgumentError in Devise::RegistrationsController\#new [\#750](https://github.com/lynndylanhurley/devise_token_auth/issues/750) +- OAuth \(GitHub\) redirects to callback url twice [\#749](https://github.com/lynndylanhurley/devise_token_auth/issues/749) +- Rails 5 API deployed as microservices [\#741](https://github.com/lynndylanhurley/devise_token_auth/issues/741) +- Query params left in url after facebook login cause authentication to fail on refresh [\#734](https://github.com/lynndylanhurley/devise_token_auth/issues/734) +- Can't permit parameters in rails engine [\#731](https://github.com/lynndylanhurley/devise_token_auth/issues/731) +- Cannot integrate with omniauth-facebook [\#729](https://github.com/lynndylanhurley/devise_token_auth/issues/729) +- Two models, one not working [\#726](https://github.com/lynndylanhurley/devise_token_auth/issues/726) +- API response bodies are empty when using active\_model\_serializers [\#715](https://github.com/lynndylanhurley/devise_token_auth/issues/715) +- /sign\_out route is returning 404 not found [\#713](https://github.com/lynndylanhurley/devise_token_auth/issues/713) +- Why is `tokens` field a json type and how to create a query based on inside values? [\#707](https://github.com/lynndylanhurley/devise_token_auth/issues/707) +- Deprecation Error Message on 5.0 [\#698](https://github.com/lynndylanhurley/devise_token_auth/issues/698) +- "Covert Redirect" Vulnerability [\#696](https://github.com/lynndylanhurley/devise_token_auth/issues/696) +- No route matches \[POST\] "/api/v1/auth" [\#694](https://github.com/lynndylanhurley/devise_token_auth/issues/694) +- Got this error with ActiveAdmin "wrong number of arguments \(1 for 0\)" [\#692](https://github.com/lynndylanhurley/devise_token_auth/issues/692) +- using devise\_token\_auth for API alongside standard devise gem for HTML view [\#689](https://github.com/lynndylanhurley/devise_token_auth/issues/689) +- No Headers after sign\_in for new Users created by Admin [\#685](https://github.com/lynndylanhurley/devise_token_auth/issues/685) +- NoMethodError \(undefined method `headers\_names' for DeviseTokenAuth:Module\) [\#684](https://github.com/lynndylanhurley/devise_token_auth/issues/684) +- Fast page refresh problem [\#683](https://github.com/lynndylanhurley/devise_token_auth/issues/683) +- IndexError: string not matched on User sign\_in [\#681](https://github.com/lynndylanhurley/devise_token_auth/issues/681) +- skip\_confirmation\_notification! not working [\#679](https://github.com/lynndylanhurley/devise_token_auth/issues/679) +- rails g devise\_token\_auth:install User auth hangs and does nothing [\#671](https://github.com/lynndylanhurley/devise_token_auth/issues/671) +- Bump version to support devise 4.1.1 [\#659](https://github.com/lynndylanhurley/devise_token_auth/issues/659) +- callback :set\_user\_by\_token has not been defined [\#649](https://github.com/lynndylanhurley/devise_token_auth/issues/649) +- Issues with active\_model\_serializers [\#644](https://github.com/lynndylanhurley/devise_token_auth/issues/644) +- Error with devise [\#643](https://github.com/lynndylanhurley/devise_token_auth/issues/643) +- undefined method `token\_validation\_response' [\#635](https://github.com/lynndylanhurley/devise_token_auth/issues/635) +- when password is reset from UI, all tokens must be removed if remove\_tokens\_after\_password\_reset is true [\#634](https://github.com/lynndylanhurley/devise_token_auth/issues/634) +- Relax devise dependency to allow 4.1 [\#631](https://github.com/lynndylanhurley/devise_token_auth/issues/631) +- Rails 5 generator doesn't insert concern [\#627](https://github.com/lynndylanhurley/devise_token_auth/issues/627) +- NoMethodError \(undefined method `find\_by\_uid'\) in production. [\#625](https://github.com/lynndylanhurley/devise_token_auth/issues/625) +- Why is password confirmation required ? [\#624](https://github.com/lynndylanhurley/devise_token_auth/issues/624) +- Curl not working for sign\_in but works on ng-token-angular [\#620](https://github.com/lynndylanhurley/devise_token_auth/issues/620) +- After Sign-in success, The following requests on Angular side are unauthorized. [\#619](https://github.com/lynndylanhurley/devise_token_auth/issues/619) +- Omniauth - Facebook app doesn't run callback url after successful Facebook authentication [\#615](https://github.com/lynndylanhurley/devise_token_auth/issues/615) +- :authenticate\_user! wired behaviour [\#614](https://github.com/lynndylanhurley/devise_token_auth/issues/614) +- current\_user is nil, request headers are all upcased and prefixed with HTML\_ [\#611](https://github.com/lynndylanhurley/devise_token_auth/issues/611) +- Problem in generated routes [\#607](https://github.com/lynndylanhurley/devise_token_auth/issues/607) +- Rails 5 API Mode - no headers in response [\#606](https://github.com/lynndylanhurley/devise_token_auth/issues/606) +- Filter chain halted as :authenticate\_user! rendered or redirected [\#603](https://github.com/lynndylanhurley/devise_token_auth/issues/603) +- 422 Unprocessable Entity when using local IP address [\#601](https://github.com/lynndylanhurley/devise_token_auth/issues/601) +- not working with latest version of active\_model\_serializers [\#600](https://github.com/lynndylanhurley/devise_token_auth/issues/600) +- overriding rendering methods in devise\_token\_auth [\#597](https://github.com/lynndylanhurley/devise_token_auth/issues/597) +- redirect\_url is missing in email instructions sent to the user for password reset [\#588](https://github.com/lynndylanhurley/devise_token_auth/issues/588) +- Unpermitted parameter: {"email":"mail@gmail.com","password":"abcdefgh","password\_confirmation":"abcdefgh"} [\#587](https://github.com/lynndylanhurley/devise_token_auth/issues/587) +- can't authenticate user when opening a new download tab [\#582](https://github.com/lynndylanhurley/devise_token_auth/issues/582) +- Mails are not being sent [\#581](https://github.com/lynndylanhurley/devise_token_auth/issues/581) +- current\_user seems to be nil after doing requests from different tabs [\#579](https://github.com/lynndylanhurley/devise_token_auth/issues/579) +- Do we have any rspec helpers to sign\_in an user? [\#577](https://github.com/lynndylanhurley/devise_token_auth/issues/577) +- Cannot override json response of authenticate\_user! [\#575](https://github.com/lynndylanhurley/devise_token_auth/issues/575) +- return custom json data after sign\_in [\#567](https://github.com/lynndylanhurley/devise_token_auth/issues/567) +- /auth/validate\_token works but getting 401 unauthorized when sending request with auth headers [\#550](https://github.com/lynndylanhurley/devise_token_auth/issues/550) +- Where is the access key of omniauth provider? [\#549](https://github.com/lynndylanhurley/devise_token_auth/issues/549) +- How this gem is different from a JWT system? [\#543](https://github.com/lynndylanhurley/devise_token_auth/issues/543) +- Improper formatting for JSON API error/success responses [\#536](https://github.com/lynndylanhurley/devise_token_auth/issues/536) +- Is it a hybrid authentication system? [\#527](https://github.com/lynndylanhurley/devise_token_auth/issues/527) +- check\_current\_password\_before\_update still requires password when resetting password [\#526](https://github.com/lynndylanhurley/devise_token_auth/issues/526) +- Manually authenticate for testing [\#521](https://github.com/lynndylanhurley/devise_token_auth/issues/521) +- Support for STI [\#517](https://github.com/lynndylanhurley/devise_token_auth/issues/517) +- DEPRECATION WARNING: alias\_method\_chain is deprecated [\#514](https://github.com/lynndylanhurley/devise_token_auth/issues/514) +- JSON responses don't fit JSON\_API requirements [\#512](https://github.com/lynndylanhurley/devise_token_auth/issues/512) +- Not working with rails 5 and devise master [\#504](https://github.com/lynndylanhurley/devise_token_auth/issues/504) +- Unpermitted parameters: confirm\_success\_url, config\_name, registration [\#501](https://github.com/lynndylanhurley/devise_token_auth/issues/501) +- set\_user\_by\_token not defined in production for rails 5 [\#500](https://github.com/lynndylanhurley/devise_token_auth/issues/500) +- Master branch no longer working with devise master branch \(version error\) [\#498](https://github.com/lynndylanhurley/devise_token_auth/issues/498) +- uid is not getting set in git revision 996b9cf23a18 [\#497](https://github.com/lynndylanhurley/devise_token_auth/issues/497) +- ve\_model\_serializer namespace [\#492](https://github.com/lynndylanhurley/devise_token_auth/issues/492) +- User remains logged in when using devise and devise\_token\_auth in the same app [\#486](https://github.com/lynndylanhurley/devise_token_auth/issues/486) +- DEPRECATION WARNING: alias\_method\_chain is deprecated. Rails 5 [\#482](https://github.com/lynndylanhurley/devise_token_auth/issues/482) +- validate\_token - resource\_name - undefined method `name' for nil:NilClass [\#480](https://github.com/lynndylanhurley/devise_token_auth/issues/480) +- Helpers being loaded for Rails API's [\#468](https://github.com/lynndylanhurley/devise_token_auth/issues/468) +- Unable to call `rails g devise\_token\_auth:install` within rails engine [\#465](https://github.com/lynndylanhurley/devise_token_auth/issues/465) +- locales `errors.messages.already\_in\_use` seems broken [\#463](https://github.com/lynndylanhurley/devise_token_auth/issues/463) +- It shows "An error occurred" after omniauth callback [\#445](https://github.com/lynndylanhurley/devise_token_auth/issues/445) +- - [\#444](https://github.com/lynndylanhurley/devise_token_auth/issues/444) +- Put Access Token in body [\#442](https://github.com/lynndylanhurley/devise_token_auth/issues/442) +- Unable to add a new param for sign up [\#440](https://github.com/lynndylanhurley/devise_token_auth/issues/440) +- Undefined method provider from devise\_toke\_auth concerns/user.rb [\#438](https://github.com/lynndylanhurley/devise_token_auth/issues/438) +- Scoped DeviseToken but it still affects the original Omniauth redirects. [\#429](https://github.com/lynndylanhurley/devise_token_auth/issues/429) +- Can't create user via api [\#422](https://github.com/lynndylanhurley/devise_token_auth/issues/422) +- Password Reset question, do I need my own form? [\#418](https://github.com/lynndylanhurley/devise_token_auth/issues/418) +- Large Size on Disk [\#415](https://github.com/lynndylanhurley/devise_token_auth/issues/415) +- The validate\_token function in the readme is missing a parameter [\#413](https://github.com/lynndylanhurley/devise_token_auth/issues/413) +- Cannot migrate database: NoMethodError: undefined method `new' for DeviseTokenAuth:Module [\#406](https://github.com/lynndylanhurley/devise_token_auth/issues/406) +- change\_headers\_on\_each\_request and batch requests [\#403](https://github.com/lynndylanhurley/devise_token_auth/issues/403) +- Multiple users, returning\(and creating\) wrong model's auth token [\#399](https://github.com/lynndylanhurley/devise_token_auth/issues/399) +- Can't verify CSRF token authenticity [\#398](https://github.com/lynndylanhurley/devise_token_auth/issues/398) +- uninitialized constant DeviseTokenAuth::OmniauthCallbacksController::BCrypt [\#393](https://github.com/lynndylanhurley/devise_token_auth/issues/393) +- Sign in not success. [\#388](https://github.com/lynndylanhurley/devise_token_auth/issues/388) +- password length [\#380](https://github.com/lynndylanhurley/devise_token_auth/issues/380) +- Devise token auth not found routing error [\#379](https://github.com/lynndylanhurley/devise_token_auth/issues/379) +- Defining a custom primary key [\#378](https://github.com/lynndylanhurley/devise_token_auth/issues/378) +- seeing other users data after login/out with different users on ionic [\#375](https://github.com/lynndylanhurley/devise_token_auth/issues/375) +- omniauth: when redirecting, user object should not be serialized into url [\#368](https://github.com/lynndylanhurley/devise_token_auth/issues/368) +- getting ng-token-auth and devise\_token\_auth to work with OAuth in ionic InAppBrowser [\#367](https://github.com/lynndylanhurley/devise_token_auth/issues/367) +- omniauth callback redirect not working properly when using namespace/scope [\#362](https://github.com/lynndylanhurley/devise_token_auth/issues/362) +- invalid token in method set\_user\_by\_token on RegistrationsController\#update [\#357](https://github.com/lynndylanhurley/devise_token_auth/issues/357) +- Allow devise patch version updates [\#351](https://github.com/lynndylanhurley/devise_token_auth/issues/351) +- Error validating token [\#348](https://github.com/lynndylanhurley/devise_token_auth/issues/348) +- Restricting access to controllers methods [\#340](https://github.com/lynndylanhurley/devise_token_auth/issues/340) +- Allow for HTTP Basic Auth ? [\#337](https://github.com/lynndylanhurley/devise_token_auth/issues/337) +- Allow Omniauth user reset password [\#335](https://github.com/lynndylanhurley/devise_token_auth/issues/335) +- NameError \(uninitialized constant DeviseTokenAuth::Concerns::User::BCrypt\) [\#333](https://github.com/lynndylanhurley/devise_token_auth/issues/333) +- Unpermitted parameters: format, session [\#328](https://github.com/lynndylanhurley/devise_token_auth/issues/328) +- Concern causes app to connect to database when precompiling assets. [\#327](https://github.com/lynndylanhurley/devise_token_auth/issues/327) +- devise token auth + Save Facebook auth\_hash info in database [\#326](https://github.com/lynndylanhurley/devise_token_auth/issues/326) +- Error sending password reset email when not using confirmable \(reopened \#124\) [\#321](https://github.com/lynndylanhurley/devise_token_auth/issues/321) +- Routing error / Preflight request / OPTIONS [\#320](https://github.com/lynndylanhurley/devise_token_auth/issues/320) +- delete tokens after password change [\#318](https://github.com/lynndylanhurley/devise_token_auth/issues/318) +- Can't authorize \(user\_signed\_in? always show false\) [\#315](https://github.com/lynndylanhurley/devise_token_auth/issues/315) +- Warden::SessionSerializer - wrong number of arguments \(2 for 1\) [\#312](https://github.com/lynndylanhurley/devise_token_auth/issues/312) +- The action 'twitter' could not be found for DeviseTokenAuth::OmniauthCallbacksController [\#309](https://github.com/lynndylanhurley/devise_token_auth/issues/309) +- Having 401 Unauthorized only with mobile [\#305](https://github.com/lynndylanhurley/devise_token_auth/issues/305) +- remove unused nickname, image from user object [\#304](https://github.com/lynndylanhurley/devise_token_auth/issues/304) +- HI, This is more of a doubt since I could not finding anything related to this in your documentation. [\#300](https://github.com/lynndylanhurley/devise_token_auth/issues/300) +- Getting 401's when making requests using iOS/Android clients [\#299](https://github.com/lynndylanhurley/devise_token_auth/issues/299) +- undefined method `tokens' for \#\ [\#297](https://github.com/lynndylanhurley/devise_token_auth/issues/297) +- Confirmation URL giving bad arguments [\#293](https://github.com/lynndylanhurley/devise_token_auth/issues/293) +- set\_user\_by\_token not called in overriden controller [\#291](https://github.com/lynndylanhurley/devise_token_auth/issues/291) +- Question: Should we send password reset instructions to unconfirmed emails? [\#287](https://github.com/lynndylanhurley/devise_token_auth/issues/287) +- NoMethodError \(undefined method `\[\]' for nil:NilClass\): [\#286](https://github.com/lynndylanhurley/devise_token_auth/issues/286) +- Facebook omniauth redirection is missing url when testing on localhost [\#285](https://github.com/lynndylanhurley/devise_token_auth/issues/285) +- No route matches \[GET\] "/users/facebook/callback" [\#280](https://github.com/lynndylanhurley/devise_token_auth/issues/280) +- No route matches \[GET\] "/omniauth/:provider" [\#278](https://github.com/lynndylanhurley/devise_token_auth/issues/278) +- How to refresh token/expiry? [\#275](https://github.com/lynndylanhurley/devise_token_auth/issues/275) +- wrong number of arguments \(1 for 0\): in DeviseTokenAuth::RegistrationsController\#create [\#274](https://github.com/lynndylanhurley/devise_token_auth/issues/274) +- Can not save a user with nil tokens attribute [\#271](https://github.com/lynndylanhurley/devise_token_auth/issues/271) +- Shouldn't validate\_token param be access-token, not auth\_token? [\#270](https://github.com/lynndylanhurley/devise_token_auth/issues/270) +- include associations on login [\#269](https://github.com/lynndylanhurley/devise_token_auth/issues/269) +- Failure route not handled [\#262](https://github.com/lynndylanhurley/devise_token_auth/issues/262) +- Getting Unauthorized error even after sending the correct token, uid and client [\#261](https://github.com/lynndylanhurley/devise_token_auth/issues/261) +- Weird error message [\#259](https://github.com/lynndylanhurley/devise_token_auth/issues/259) +- undefined method `provider' for \#\ [\#257](https://github.com/lynndylanhurley/devise_token_auth/issues/257) +- Custom Serializer like ActiveModel Serializer [\#249](https://github.com/lynndylanhurley/devise_token_auth/issues/249) +- File download with query params [\#246](https://github.com/lynndylanhurley/devise_token_auth/issues/246) +- Info: is devise\_token\_auth compatible with rails 3.2.19? [\#245](https://github.com/lynndylanhurley/devise_token_auth/issues/245) +- Headers required for different methods [\#243](https://github.com/lynndylanhurley/devise_token_auth/issues/243) +- Unpermitted parameters: format, session, lang [\#239](https://github.com/lynndylanhurley/devise_token_auth/issues/239) +- On sign\_in, devise\_token\_auth expects the uid to be the same as the email [\#237](https://github.com/lynndylanhurley/devise_token_auth/issues/237) +- Name conflict with inherited\_resources [\#236](https://github.com/lynndylanhurley/devise_token_auth/issues/236) +- sign\_in will not fetch the token [\#234](https://github.com/lynndylanhurley/devise_token_auth/issues/234) +- Remove \('\#'\) symbol when using html5mode in locationProvider [\#232](https://github.com/lynndylanhurley/devise_token_auth/issues/232) +- Log in request 401 error [\#231](https://github.com/lynndylanhurley/devise_token_auth/issues/231) +- User Registration - "email address already in use" when it is unique [\#230](https://github.com/lynndylanhurley/devise_token_auth/issues/230) +- Devise email validation disabled...why? [\#229](https://github.com/lynndylanhurley/devise_token_auth/issues/229) +- confirm\_success\_url error not working [\#226](https://github.com/lynndylanhurley/devise_token_auth/issues/226) +- pending\_reconfirmation called when confirmable isn't used [\#224](https://github.com/lynndylanhurley/devise_token_auth/issues/224) +- omniauth\_success.html.erb JSON bug [\#221](https://github.com/lynndylanhurley/devise_token_auth/issues/221) +- Using devise\_token\_auth and ng\_token\_auth with angularJS in an Ionic Hybrid application [\#218](https://github.com/lynndylanhurley/devise_token_auth/issues/218) +- Where can I got token? [\#217](https://github.com/lynndylanhurley/devise_token_auth/issues/217) +- URI fragment prevent to send params in Confirmation URL [\#213](https://github.com/lynndylanhurley/devise_token_auth/issues/213) +- Generating many client tokens [\#210](https://github.com/lynndylanhurley/devise_token_auth/issues/210) +- Limit tokens hash? [\#208](https://github.com/lynndylanhurley/devise_token_auth/issues/208) +- 500 error returned when no data is POSTed to registration controller [\#203](https://github.com/lynndylanhurley/devise_token_auth/issues/203) +- undefined method `match' for nil:NilClass [\#201](https://github.com/lynndylanhurley/devise_token_auth/issues/201) +- DELETE method becoming OPTIONS @ Heroku [\#197](https://github.com/lynndylanhurley/devise_token_auth/issues/197) +- 40 Mb log file and 1 minute to have token with curl [\#195](https://github.com/lynndylanhurley/devise_token_auth/issues/195) +- 401 unauthorized [\#193](https://github.com/lynndylanhurley/devise_token_auth/issues/193) +- GET requests to sign\_in shouldn't raise an exception [\#190](https://github.com/lynndylanhurley/devise_token_auth/issues/190) +- Api not locked by default [\#189](https://github.com/lynndylanhurley/devise_token_auth/issues/189) +- Rails 4.1 [\#187](https://github.com/lynndylanhurley/devise_token_auth/issues/187) +- Unable to override OmniauthCallbacksController\#redirect\_callbacks [\#186](https://github.com/lynndylanhurley/devise_token_auth/issues/186) +- Devise and devise\_token\_auth omniauth callbacks [\#184](https://github.com/lynndylanhurley/devise_token_auth/issues/184) +- Token based authentication with no sessions [\#183](https://github.com/lynndylanhurley/devise_token_auth/issues/183) +- undefined method `authenticate\_user!' [\#182](https://github.com/lynndylanhurley/devise_token_auth/issues/182) +- confirm\_success\_url shouldn't be a required param [\#176](https://github.com/lynndylanhurley/devise_token_auth/issues/176) +- Provide an OAuth implementation for native apps [\#175](https://github.com/lynndylanhurley/devise_token_auth/issues/175) +- getting an argument error when trying to use omniauth [\#174](https://github.com/lynndylanhurley/devise_token_auth/issues/174) +- Sign in via username doesn't seem to work correctly. [\#173](https://github.com/lynndylanhurley/devise_token_auth/issues/173) +- Cannot use + sign in email address. [\#171](https://github.com/lynndylanhurley/devise_token_auth/issues/171) +- How can i authenticate using curl and get private entries ! [\#167](https://github.com/lynndylanhurley/devise_token_auth/issues/167) +- Pessimistic Locking produces ArgumentError [\#165](https://github.com/lynndylanhurley/devise_token_auth/issues/165) +- POTENTIAL SECURITY RISK: Setting confirm\_success\_url and redirect\_url via API [\#162](https://github.com/lynndylanhurley/devise_token_auth/issues/162) +- Sign out just on client side ? [\#161](https://github.com/lynndylanhurley/devise_token_auth/issues/161) +- Unpermitted parameter: redirect\_url [\#160](https://github.com/lynndylanhurley/devise_token_auth/issues/160) +- Issues using devise and devise\_token\_auth [\#159](https://github.com/lynndylanhurley/devise_token_auth/issues/159) +- Add role based authorization [\#158](https://github.com/lynndylanhurley/devise_token_auth/issues/158) +- Not compatible with ActiveAdmin [\#156](https://github.com/lynndylanhurley/devise_token_auth/issues/156) +- \[Duplicate\] is devise\_invitable supported? [\#154](https://github.com/lynndylanhurley/devise_token_auth/issues/154) +- User can register with a "false" email [\#149](https://github.com/lynndylanhurley/devise_token_auth/issues/149) +- /validate\_token [\#148](https://github.com/lynndylanhurley/devise_token_auth/issues/148) +- Email confirmation link [\#147](https://github.com/lynndylanhurley/devise_token_auth/issues/147) +- Tokens field on database [\#146](https://github.com/lynndylanhurley/devise_token_auth/issues/146) +- Twitter OAuth always throughs CookieOverflow [\#145](https://github.com/lynndylanhurley/devise_token_auth/issues/145) +- Is there a way to configure apiUrl for both dev and prod? [\#144](https://github.com/lynndylanhurley/devise_token_auth/issues/144) +- Getting 401 unauthorized on login attempt [\#142](https://github.com/lynndylanhurley/devise_token_auth/issues/142) +- Comparing with jwt [\#140](https://github.com/lynndylanhurley/devise_token_auth/issues/140) +- Can't get omniauth to work \(error in redirect\_callbacks\) [\#139](https://github.com/lynndylanhurley/devise_token_auth/issues/139) +- Change controller inheritance [\#138](https://github.com/lynndylanhurley/devise_token_auth/issues/138) +- Reset Password call returns 400 for Not Found user [\#137](https://github.com/lynndylanhurley/devise_token_auth/issues/137) +- The gem is too big. Please take care of it. [\#136](https://github.com/lynndylanhurley/devise_token_auth/issues/136) +- Error when loging with facebook the second time without logout [\#135](https://github.com/lynndylanhurley/devise_token_auth/issues/135) +- OmniAuth redirect doesn't work if using the generated mount\_devise\_token route [\#133](https://github.com/lynndylanhurley/devise_token_auth/issues/133) +- Missing template /omniauth\_response [\#132](https://github.com/lynndylanhurley/devise_token_auth/issues/132) +- Unpermitted parameter: session [\#130](https://github.com/lynndylanhurley/devise_token_auth/issues/130) +- OAuth error: We're sorry, but something went wrong [\#129](https://github.com/lynndylanhurley/devise_token_auth/issues/129) +- Would it be useful to integrate login with username ? [\#127](https://github.com/lynndylanhurley/devise_token_auth/issues/127) +- Sign in with login instead of email [\#126](https://github.com/lynndylanhurley/devise_token_auth/issues/126) +- Error sending password reset email when not using confirmable [\#124](https://github.com/lynndylanhurley/devise_token_auth/issues/124) +- Using expired token for parallel calls [\#123](https://github.com/lynndylanhurley/devise_token_auth/issues/123) +- User tokens don't properly deserialize [\#121](https://github.com/lynndylanhurley/devise_token_auth/issues/121) +- OmniauthCallbacksController\#omniauth\_success wrong number of arguments \(1 for 0\) [\#119](https://github.com/lynndylanhurley/devise_token_auth/issues/119) +- Could not load 'omniauth' [\#118](https://github.com/lynndylanhurley/devise_token_auth/issues/118) +- bad argument \(expected URI object or URI string\) [\#116](https://github.com/lynndylanhurley/devise_token_auth/issues/116) +- devise\_token\_auth for public API, but devise for rest of app? [\#114](https://github.com/lynndylanhurley/devise_token_auth/issues/114) +- Omniauthable deleted on UsersConcern : Why ? [\#111](https://github.com/lynndylanhurley/devise_token_auth/issues/111) +- Unrequired route [\#110](https://github.com/lynndylanhurley/devise_token_auth/issues/110) +- raises NoMethodError instead of displaying error when email is missing [\#108](https://github.com/lynndylanhurley/devise_token_auth/issues/108) +- Error with RailsAdmin. "The action 'new' could not be found for DeviseTokenAuth::SessionsController" [\#107](https://github.com/lynndylanhurley/devise_token_auth/issues/107) +- Circular dependency detected while autoloading constant Api [\#106](https://github.com/lynndylanhurley/devise_token_auth/issues/106) +- Can't Authenticate via cURL [\#105](https://github.com/lynndylanhurley/devise_token_auth/issues/105) +- Unpermitted parameters: user, registration [\#104](https://github.com/lynndylanhurley/devise_token_auth/issues/104) +- BCrypt::Errors::InvalidSalt errors [\#103](https://github.com/lynndylanhurley/devise_token_auth/issues/103) +- Active job token expiring integration [\#102](https://github.com/lynndylanhurley/devise_token_auth/issues/102) +- The action 'new' could not be found for DeviseTokenAuth::RegistrationsController [\#100](https://github.com/lynndylanhurley/devise_token_auth/issues/100) +- Disable confirmable [\#99](https://github.com/lynndylanhurley/devise_token_auth/issues/99) +- responders - rails 4.2 [\#98](https://github.com/lynndylanhurley/devise_token_auth/issues/98) +- forward skip to devise [\#97](https://github.com/lynndylanhurley/devise_token_auth/issues/97) +- API versioning the devise scope of token validation and ominiauth controller path will wrap up [\#96](https://github.com/lynndylanhurley/devise_token_auth/issues/96) +- Overwriting default "from" email address [\#94](https://github.com/lynndylanhurley/devise_token_auth/issues/94) +- uninitialized constant DeviseTokenAuth [\#92](https://github.com/lynndylanhurley/devise_token_auth/issues/92) +- change\_headers\_on\_each\_request not working expiry header empty [\#90](https://github.com/lynndylanhurley/devise_token_auth/issues/90) +- Gem render consistency [\#87](https://github.com/lynndylanhurley/devise_token_auth/issues/87) +- Sample Sessions Controller for logging in via Rails View. [\#86](https://github.com/lynndylanhurley/devise_token_auth/issues/86) +- Change authorization key: Use phone\_number instead of email [\#84](https://github.com/lynndylanhurley/devise_token_auth/issues/84) +- Conflict with active\_admin gem [\#83](https://github.com/lynndylanhurley/devise_token_auth/issues/83) +- NoMethodError in DeviseTokenAuth::OmniauthCallbacksController\#redirect\_callbacks [\#82](https://github.com/lynndylanhurley/devise_token_auth/issues/82) +- All the APIs are getting 'Authorized users only' [\#81](https://github.com/lynndylanhurley/devise_token_auth/issues/81) +- Is Devise option Rememberable required ? [\#80](https://github.com/lynndylanhurley/devise_token_auth/issues/80) +- Problem with skip\_confirmation! [\#78](https://github.com/lynndylanhurley/devise_token_auth/issues/78) +- Cannot reset password if registered by omniauth [\#77](https://github.com/lynndylanhurley/devise_token_auth/issues/77) +- NoMethodError at /omniauth/facebook/callback - undefined method `\[\]' for nil:NilClass [\#76](https://github.com/lynndylanhurley/devise_token_auth/issues/76) +- Remove dependency on ActiveRecord [\#72](https://github.com/lynndylanhurley/devise_token_auth/issues/72) +- Skipping Registrations Controller Altogether [\#70](https://github.com/lynndylanhurley/devise_token_auth/issues/70) +- Problem in validate\_token if the model is in a namespace [\#69](https://github.com/lynndylanhurley/devise_token_auth/issues/69) +- Cannot send confirmation email if there is no 'User' model [\#68](https://github.com/lynndylanhurley/devise_token_auth/issues/68) +- Better guidelines for contributors [\#65](https://github.com/lynndylanhurley/devise_token_auth/issues/65) +- admin namespace [\#63](https://github.com/lynndylanhurley/devise_token_auth/issues/63) +- Devise trackable module not working [\#62](https://github.com/lynndylanhurley/devise_token_auth/issues/62) +- Devise\_token\_auth without OmniAuth authentication [\#60](https://github.com/lynndylanhurley/devise_token_auth/issues/60) +- Reset Password error [\#59](https://github.com/lynndylanhurley/devise_token_auth/issues/59) +- Confirmable - unconfirmed email [\#58](https://github.com/lynndylanhurley/devise_token_auth/issues/58) +- Email Column Isn't Used for Database Authentication [\#56](https://github.com/lynndylanhurley/devise_token_auth/issues/56) +- Unique Key for Provider and UID Combination [\#55](https://github.com/lynndylanhurley/devise_token_auth/issues/55) +- User Info in separate table or removed [\#53](https://github.com/lynndylanhurley/devise_token_auth/issues/53) +- rename @user to @resource [\#48](https://github.com/lynndylanhurley/devise_token_auth/issues/48) +- Active\_admin issue [\#47](https://github.com/lynndylanhurley/devise_token_auth/issues/47) +- Possible Logout Issue [\#46](https://github.com/lynndylanhurley/devise_token_auth/issues/46) +- Routes not appended to routes.rb [\#45](https://github.com/lynndylanhurley/devise_token_auth/issues/45) +- Return resource.errors.full\_messages in addition to resource.errors [\#44](https://github.com/lynndylanhurley/devise_token_auth/issues/44) +- Devise and Devise\_Token\_Auth in api namespace [\#43](https://github.com/lynndylanhurley/devise_token_auth/issues/43) +- Trackable attributes are not being updated. [\#42](https://github.com/lynndylanhurley/devise_token_auth/issues/42) +- Avoid using respond\_to in application controller [\#41](https://github.com/lynndylanhurley/devise_token_auth/issues/41) +- devise\_token\_auth assumes you want the :confirmable functionality [\#40](https://github.com/lynndylanhurley/devise_token_auth/issues/40) +- undefined method `match' for nil:NilClass [\#39](https://github.com/lynndylanhurley/devise_token_auth/issues/39) +- Expired token aren't removed when session expires [\#38](https://github.com/lynndylanhurley/devise_token_auth/issues/38) +- sign\_up helper [\#37](https://github.com/lynndylanhurley/devise_token_auth/issues/37) +- self.tokens\[client\_id\]\['token'\] != token [\#30](https://github.com/lynndylanhurley/devise_token_auth/issues/30) +- How is the uid generated for non-omniauth users? [\#29](https://github.com/lynndylanhurley/devise_token_auth/issues/29) +- Access to current\_user variable? [\#28](https://github.com/lynndylanhurley/devise_token_auth/issues/28) +- Filter chain halted as :require\_no\_authentication [\#27](https://github.com/lynndylanhurley/devise_token_auth/issues/27) +- Allow additional parameters for registration [\#25](https://github.com/lynndylanhurley/devise_token_auth/issues/25) +- Cannot add more parameters at sign\_up [\#22](https://github.com/lynndylanhurley/devise_token_auth/issues/22) +- Error on Registration [\#21](https://github.com/lynndylanhurley/devise_token_auth/issues/21) +- Error with authentication [\#20](https://github.com/lynndylanhurley/devise_token_auth/issues/20) +- Cascade of Issues with Omniauth\(?\) [\#18](https://github.com/lynndylanhurley/devise_token_auth/issues/18) +- Batch Requests Respond with Original Auth Token [\#17](https://github.com/lynndylanhurley/devise_token_auth/issues/17) +- Sign out with email provider error [\#16](https://github.com/lynndylanhurley/devise_token_auth/issues/16) +- sessions\_controller.rb [\#12](https://github.com/lynndylanhurley/devise_token_auth/issues/12) +- Github login in example is broken [\#10](https://github.com/lynndylanhurley/devise_token_auth/issues/10) +- Facebook auth is broken [\#9](https://github.com/lynndylanhurley/devise_token_auth/issues/9) +- Generator is not working [\#8](https://github.com/lynndylanhurley/devise_token_auth/issues/8) +- Test ticket from Code Climate [\#6](https://github.com/lynndylanhurley/devise_token_auth/issues/6) +- Test ticket from Code Climate [\#5](https://github.com/lynndylanhurley/devise_token_auth/issues/5) +- extending the devise\_token\_auth user model [\#4](https://github.com/lynndylanhurley/devise_token_auth/issues/4) +- A few ideas [\#3](https://github.com/lynndylanhurley/devise_token_auth/issues/3) +- Google Oauth2 does not set cookies in production. [\#1](https://github.com/lynndylanhurley/devise_token_auth/issues/1) + +**Merged pull requests:** + +- Translate message: Authorized users only through devise [\#883](https://github.com/lynndylanhurley/devise_token_auth/pull/883) ([vincenzodev](https://github.com/vincenzodev)) +- Updated generator test code to work with rails 5 [\#872](https://github.com/lynndylanhurley/devise_token_auth/pull/872) ([jrhee17](https://github.com/jrhee17)) +- use URI::HTTPS to generate HTTPS redirects [\#864](https://github.com/lynndylanhurley/devise_token_auth/pull/864) ([cgc](https://github.com/cgc)) +- Rename find\_by methods [\#860](https://github.com/lynndylanhurley/devise_token_auth/pull/860) ([alex-lairan](https://github.com/alex-lairan)) +- Support for Devise 4.2.1 [\#852](https://github.com/lynndylanhurley/devise_token_auth/pull/852) ([ckho](https://github.com/ckho)) +- Add Albanian locale [\#842](https://github.com/lynndylanhurley/devise_token_auth/pull/842) ([fatosmorina](https://github.com/fatosmorina)) +- Update german translation. [\#816](https://github.com/lynndylanhurley/devise_token_auth/pull/816) ([gobijan](https://github.com/gobijan)) +- Prevent getting table info if not connected to db [\#814](https://github.com/lynndylanhurley/devise_token_auth/pull/814) ([cbliard](https://github.com/cbliard)) +- Add support for italian locale [\#811](https://github.com/lynndylanhurley/devise_token_auth/pull/811) ([Chosko](https://github.com/Chosko)) +- Fix privacy issue with password reset request [\#808](https://github.com/lynndylanhurley/devise_token_auth/pull/808) ([biomancer](https://github.com/biomancer)) +- Add missing parameter :redirect\_url, fixes \#805 [\#806](https://github.com/lynndylanhurley/devise_token_auth/pull/806) ([Rush](https://github.com/Rush)) +- Fix language errors in German locale [\#800](https://github.com/lynndylanhurley/devise_token_auth/pull/800) ([morgler](https://github.com/morgler)) +- Don't send extra data on request password reset [\#798](https://github.com/lynndylanhurley/devise_token_auth/pull/798) ([Mrjaco12](https://github.com/Mrjaco12)) +- Travis: use the code\_climate addon config [\#786](https://github.com/lynndylanhurley/devise_token_auth/pull/786) ([olleolleolle](https://github.com/olleolleolle)) +- Update link [\#782](https://github.com/lynndylanhurley/devise_token_auth/pull/782) ([dijonkitchen](https://github.com/dijonkitchen)) +- Add index for confirmation\_token [\#767](https://github.com/lynndylanhurley/devise_token_auth/pull/767) ([dijonkitchen](https://github.com/dijonkitchen)) +- Fixes constructing redirect\_route [\#765](https://github.com/lynndylanhurley/devise_token_auth/pull/765) ([piotrkaczmarek](https://github.com/piotrkaczmarek)) +- Use standart ActiveRecord error message for email uniqueness validation [\#746](https://github.com/lynndylanhurley/devise_token_auth/pull/746) ([mpugach](https://github.com/mpugach)) +- Add Romanian locale. [\#743](https://github.com/lynndylanhurley/devise_token_auth/pull/743) ([razvanmitre](https://github.com/razvanmitre)) +- Ruby syntax: replace and/not with &&/! [\#733](https://github.com/lynndylanhurley/devise_token_auth/pull/733) ([olleolleolle](https://github.com/olleolleolle)) +- Update indexes on template [\#724](https://github.com/lynndylanhurley/devise_token_auth/pull/724) ([dijonkitchen](https://github.com/dijonkitchen)) +- Add an extra line to the "contributing" list [\#720](https://github.com/lynndylanhurley/devise_token_auth/pull/720) ([jahammo2](https://github.com/jahammo2)) +- Fix grammar [\#712](https://github.com/lynndylanhurley/devise_token_auth/pull/712) ([dijonkitchen](https://github.com/dijonkitchen)) +- Added reference to Angular2-Token to README [\#710](https://github.com/lynndylanhurley/devise_token_auth/pull/710) ([neroniaky](https://github.com/neroniaky)) +- feat\(whitelist\): add wildcard support for redirect\_whitelist patterns [\#709](https://github.com/lynndylanhurley/devise_token_auth/pull/709) ([booleanbetrayal](https://github.com/booleanbetrayal)) +- Fix Migration Deprecation Warning [\#700](https://github.com/lynndylanhurley/devise_token_auth/pull/700) ([juddey](https://github.com/juddey)) +- Apply `redirect\_whitelist` to OAuth redirect URI. [\#699](https://github.com/lynndylanhurley/devise_token_auth/pull/699) ([lynndylanhurley](https://github.com/lynndylanhurley)) +- add zh-CN.yml [\#697](https://github.com/lynndylanhurley/devise_token_auth/pull/697) ([halfray](https://github.com/halfray)) +- update README.md [\#693](https://github.com/lynndylanhurley/devise_token_auth/pull/693) ([nhattan](https://github.com/nhattan)) +- Fix for issue \#600 [\#674](https://github.com/lynndylanhurley/devise_token_auth/pull/674) ([milep](https://github.com/milep)) +- Use lockable devise option and unlock controller overwrite [\#669](https://github.com/lynndylanhurley/devise_token_auth/pull/669) ([genaromadrid](https://github.com/genaromadrid)) +- Fix setup config example in README [\#665](https://github.com/lynndylanhurley/devise_token_auth/pull/665) ([guich-wo](https://github.com/guich-wo)) +- added bypass\_sign\_in for next version of Devise [\#663](https://github.com/lynndylanhurley/devise_token_auth/pull/663) ([KendallPark](https://github.com/KendallPark)) +- fix method 'is\_json\_api' with active\_model\_serialier v 0.10.0 [\#651](https://github.com/lynndylanhurley/devise_token_auth/pull/651) ([woodcrust](https://github.com/woodcrust)) +- Tokens count overmuch fixed [\#650](https://github.com/lynndylanhurley/devise_token_auth/pull/650) ([JerryGreen](https://github.com/JerryGreen)) +- updates config wrapper to conform with newer idiom [\#648](https://github.com/lynndylanhurley/devise_token_auth/pull/648) ([bvandgrift](https://github.com/bvandgrift)) +- Adding support for devise 4.1.1 [\#642](https://github.com/lynndylanhurley/devise_token_auth/pull/642) ([iainmcg](https://github.com/iainmcg)) +- Updating Devise dependency to max 4.1.1 [\#641](https://github.com/lynndylanhurley/devise_token_auth/pull/641) ([TGRGIT](https://github.com/TGRGIT)) +- Fix yields from controller actions [\#638](https://github.com/lynndylanhurley/devise_token_auth/pull/638) ([tiagojsag](https://github.com/tiagojsag)) +- Fix generator to correctly inject content into the user model in rails 5 [\#636](https://github.com/lynndylanhurley/devise_token_auth/pull/636) ([ethangk](https://github.com/ethangk)) +- fix spelling in comment on token auth concern [\#632](https://github.com/lynndylanhurley/devise_token_auth/pull/632) ([dandlezzz](https://github.com/dandlezzz)) +- fixed devise deprecation warning for config.email\_regexp [\#618](https://github.com/lynndylanhurley/devise_token_auth/pull/618) ([lemuelbarango](https://github.com/lemuelbarango)) +- Revert "Update readme for headers names" [\#592](https://github.com/lynndylanhurley/devise_token_auth/pull/592) ([ash1day](https://github.com/ash1day)) +- Update readme for headers names [\#589](https://github.com/lynndylanhurley/devise_token_auth/pull/589) ([ash1day](https://github.com/ash1day)) +- Add info to README [\#585](https://github.com/lynndylanhurley/devise_token_auth/pull/585) ([ghost](https://github.com/ghost)) +- Fix typo and remove trailing spaces [\#578](https://github.com/lynndylanhurley/devise_token_auth/pull/578) ([ash1day](https://github.com/ash1day)) +- allowing authenticating using headers as well as a post request [\#576](https://github.com/lynndylanhurley/devise_token_auth/pull/576) ([ingolfured](https://github.com/ingolfured)) +- Whitespace: tabs removed [\#574](https://github.com/lynndylanhurley/devise_token_auth/pull/574) ([olleolleolle](https://github.com/olleolleolle)) +- Added dutch translations [\#571](https://github.com/lynndylanhurley/devise_token_auth/pull/571) ([nschmoller](https://github.com/nschmoller)) +- now possible to change headers names in the config file [\#569](https://github.com/lynndylanhurley/devise_token_auth/pull/569) ([ingolfured](https://github.com/ingolfured)) +- User concern: Ensure fallback is in place [\#564](https://github.com/lynndylanhurley/devise_token_auth/pull/564) ([olleolleolle](https://github.com/olleolleolle)) +- Return resource with top-level 'type' member. [\#562](https://github.com/lynndylanhurley/devise_token_auth/pull/562) ([ruimiguelsantos](https://github.com/ruimiguelsantos)) +- Fix devise mapping [\#540](https://github.com/lynndylanhurley/devise_token_auth/pull/540) ([merqlove](https://github.com/merqlove)) +- Make all json responses to be json\_api compliant [\#537](https://github.com/lynndylanhurley/devise_token_auth/pull/537) ([djsegal](https://github.com/djsegal)) +- Avoid sending auth headers if while processing used token is cleared [\#531](https://github.com/lynndylanhurley/devise_token_auth/pull/531) ([virginia-rodriguez](https://github.com/virginia-rodriguez)) +- Add Japanese locale and fix typo [\#530](https://github.com/lynndylanhurley/devise_token_auth/pull/530) ([metalunk](https://github.com/metalunk)) +- Added omniauth post route [\#528](https://github.com/lynndylanhurley/devise_token_auth/pull/528) ([v3rtx](https://github.com/v3rtx)) +- Extract model callbacks [\#525](https://github.com/lynndylanhurley/devise_token_auth/pull/525) ([merqlove](https://github.com/merqlove)) +- create token when no client\_id token [\#523](https://github.com/lynndylanhurley/devise_token_auth/pull/523) ([charlesdg](https://github.com/charlesdg)) +- Fix enable\_standard\_devise\_support in initializer [\#518](https://github.com/lynndylanhurley/devise_token_auth/pull/518) ([halilim](https://github.com/halilim)) +- Make render\_create\_success render valid json\_api [\#513](https://github.com/lynndylanhurley/devise_token_auth/pull/513) ([djsegal](https://github.com/djsegal)) +- Prevent raise of exception if set\_user\_by\_token not defined [\#511](https://github.com/lynndylanhurley/devise_token_auth/pull/511) ([jeryRazakarison](https://github.com/jeryRazakarison)) +- send\_on\_create\_confirmation\_instructions callback isn't defined \(rails 5\) [\#508](https://github.com/lynndylanhurley/devise_token_auth/pull/508) ([fivetwentysix](https://github.com/fivetwentysix)) +- \[REBASE\] Fix rails 5 deprecation and devise parameter sanitization [\#507](https://github.com/lynndylanhurley/devise_token_auth/pull/507) ([fivetwentysix](https://github.com/fivetwentysix)) +- remove deprecations from RegistrationsController [\#506](https://github.com/lynndylanhurley/devise_token_auth/pull/506) ([fivetwentysix](https://github.com/fivetwentysix)) +- Allow new devise version for rails 5 compatibility [\#499](https://github.com/lynndylanhurley/devise_token_auth/pull/499) ([djsegal](https://github.com/djsegal)) +- Spelling mistake [\#493](https://github.com/lynndylanhurley/devise_token_auth/pull/493) ([Tom-Tom](https://github.com/Tom-Tom)) +- Improve Brazilian Portuguese locale [\#491](https://github.com/lynndylanhurley/devise_token_auth/pull/491) ([ssouza](https://github.com/ssouza)) +- fix namespaced mapping name [\#484](https://github.com/lynndylanhurley/devise_token_auth/pull/484) ([paulosoares86](https://github.com/paulosoares86)) +- Locale file for both zh-TW and zh-HK [\#483](https://github.com/lynndylanhurley/devise_token_auth/pull/483) ([SunnyTam](https://github.com/SunnyTam)) +- Fixed typos and inconsistencies in ru.yml [\#478](https://github.com/lynndylanhurley/devise_token_auth/pull/478) ([fertingoff](https://github.com/fertingoff)) +- Fixes Issue \#362: Fixes for the omniauth redirection issue for namesp… [\#476](https://github.com/lynndylanhurley/devise_token_auth/pull/476) ([devilankur18](https://github.com/devilankur18)) +- removing old tokens when user changes passwords [\#474](https://github.com/lynndylanhurley/devise_token_auth/pull/474) ([paulosoares86](https://github.com/paulosoares86)) +- Move travis to container based configuration [\#470](https://github.com/lynndylanhurley/devise_token_auth/pull/470) ([ValentinTrinque](https://github.com/ValentinTrinque)) +- Prevent helpers being loaded for Rails API’s [\#469](https://github.com/lynndylanhurley/devise_token_auth/pull/469) ([djsegal](https://github.com/djsegal)) +- Reduce dependencies to allow Rails 5.0 [\#467](https://github.com/lynndylanhurley/devise_token_auth/pull/467) ([djsegal](https://github.com/djsegal)) +- Fix locales `errors.messages.already\_in\_use` + clean up [\#466](https://github.com/lynndylanhurley/devise_token_auth/pull/466) ([ValentinTrinque](https://github.com/ValentinTrinque)) +- Added 401 response to failed group authentication [\#446](https://github.com/lynndylanhurley/devise_token_auth/pull/446) ([rstrobl](https://github.com/rstrobl)) +- RU translations [\#441](https://github.com/lynndylanhurley/devise_token_auth/pull/441) ([yivo](https://github.com/yivo)) +- to keep coherent with devise. pt instead of pt-PT.yml [\#436](https://github.com/lynndylanhurley/devise_token_auth/pull/436) ([rmvenancio](https://github.com/rmvenancio)) +- limiting the number of concurrent devices [\#434](https://github.com/lynndylanhurley/devise_token_auth/pull/434) ([paulosoares86](https://github.com/paulosoares86)) +- Raise error in controller method [\#430](https://github.com/lynndylanhurley/devise_token_auth/pull/430) ([ArneZsng](https://github.com/ArneZsng)) +- feat\(enable-standard-devise\): allow configurable support of legacy Devise authentication [\#428](https://github.com/lynndylanhurley/devise_token_auth/pull/428) ([booleanbetrayal](https://github.com/booleanbetrayal)) +- Support for i18n in mailers views [\#427](https://github.com/lynndylanhurley/devise_token_auth/pull/427) ([ponyesteves](https://github.com/ponyesteves)) +- Fix omniauthredirection when under scopes [\#425](https://github.com/lynndylanhurley/devise_token_auth/pull/425) ([xjunior](https://github.com/xjunior)) +- Translation to German [\#423](https://github.com/lynndylanhurley/devise_token_auth/pull/423) ([haslinger](https://github.com/haslinger)) +- fix\(url\): preserve query parameters when building urls [\#421](https://github.com/lynndylanhurley/devise_token_auth/pull/421) ([nbrustein](https://github.com/nbrustein)) +- Change default message for already in use error and added to english … [\#417](https://github.com/lynndylanhurley/devise_token_auth/pull/417) ([ponyesteves](https://github.com/ponyesteves)) +- Issue \#413 [\#414](https://github.com/lynndylanhurley/devise_token_auth/pull/414) ([Carrigan](https://github.com/Carrigan)) +- Add .ruby-version entry to .gitignore [\#412](https://github.com/lynndylanhurley/devise_token_auth/pull/412) ([xymbol](https://github.com/xymbol)) +- 404 for invalid link with password reset token [\#411](https://github.com/lynndylanhurley/devise_token_auth/pull/411) ([rmvenancio](https://github.com/rmvenancio)) +- Portuguese Translation [\#409](https://github.com/lynndylanhurley/devise_token_auth/pull/409) ([rmvenancio](https://github.com/rmvenancio)) +- Added polish translation. [\#405](https://github.com/lynndylanhurley/devise_token_auth/pull/405) ([h3xed](https://github.com/h3xed)) +- Drop .ruby-version file [\#404](https://github.com/lynndylanhurley/devise_token_auth/pull/404) ([xymbol](https://github.com/xymbol)) +- Implement hook methods for customized json rendering [\#384](https://github.com/lynndylanhurley/devise_token_auth/pull/384) ([neutronz](https://github.com/neutronz)) +- Feature/password reset with check fix [\#374](https://github.com/lynndylanhurley/devise_token_auth/pull/374) ([jakubrohleder](https://github.com/jakubrohleder)) +- fix\(oauth\): fixes \#368: do not serialize the entire user object in the url when redirecting from oauth [\#371](https://github.com/lynndylanhurley/devise_token_auth/pull/371) ([nbrustein](https://github.com/nbrustein)) +- Fallback to ActiveModel translations in EmailValidator [\#369](https://github.com/lynndylanhurley/devise_token_auth/pull/369) ([yivo](https://github.com/yivo)) +- Add a Gitter chat badge to README.md [\#360](https://github.com/lynndylanhurley/devise_token_auth/pull/360) ([gitter-badger](https://github.com/gitter-badger)) +- Improvements to the docs. [\#358](https://github.com/lynndylanhurley/devise_token_auth/pull/358) ([aarongray](https://github.com/aarongray)) +- Add description to readme about the devise.rb initializer. [\#356](https://github.com/lynndylanhurley/devise_token_auth/pull/356) ([aarongray](https://github.com/aarongray)) +- Correct handling namespaced resources [\#355](https://github.com/lynndylanhurley/devise_token_auth/pull/355) ([yivo](https://github.com/yivo)) +- Fix concern not being inserted for rails-api apps. [\#350](https://github.com/lynndylanhurley/devise_token_auth/pull/350) ([aarongray](https://github.com/aarongray)) +- Add documentation to explain gotcha with rails-api. [\#349](https://github.com/lynndylanhurley/devise_token_auth/pull/349) ([aarongray](https://github.com/aarongray)) +- Fully support OmniauthCallbacksController action overrides. Fixes \#186. [\#347](https://github.com/lynndylanhurley/devise_token_auth/pull/347) ([tbloncar](https://github.com/tbloncar)) +- \#340 Restrict access to controllers methods [\#341](https://github.com/lynndylanhurley/devise_token_auth/pull/341) ([gkopylov](https://github.com/gkopylov)) +- fix\(omniauth\): fix error in setting text on redirect page [\#336](https://github.com/lynndylanhurley/devise_token_auth/pull/336) ([nbrustein](https://github.com/nbrustein)) +- add Brazilian Portuguese translation \(pt-BR\) [\#331](https://github.com/lynndylanhurley/devise_token_auth/pull/331) ([josiasds](https://github.com/josiasds)) +- Tests to ensure standard devise has greater priority than tokens [\#330](https://github.com/lynndylanhurley/devise_token_auth/pull/330) ([colavitam](https://github.com/colavitam)) +- Fixed error when using standard devise authentication [\#329](https://github.com/lynndylanhurley/devise_token_auth/pull/329) ([colavitam](https://github.com/colavitam)) +- feat\(improved-omniauth\): omniauth sameWindow and inAppBrowser flows [\#323](https://github.com/lynndylanhurley/devise_token_auth/pull/323) ([nbrustein](https://github.com/nbrustein)) +- Fix invalid omniauth redirect [\#322](https://github.com/lynndylanhurley/devise_token_auth/pull/322) ([troggy](https://github.com/troggy)) +- Old password check before password update [\#317](https://github.com/lynndylanhurley/devise_token_auth/pull/317) ([jakubrohleder](https://github.com/jakubrohleder)) +- Remove erroneous colon from before\_action callback [\#310](https://github.com/lynndylanhurley/devise_token_auth/pull/310) ([jmliu](https://github.com/jmliu)) +- Disabled serialization for JSON type columns [\#306](https://github.com/lynndylanhurley/devise_token_auth/pull/306) ([colavitam](https://github.com/colavitam)) +- Set default provider to "email" in migration [\#302](https://github.com/lynndylanhurley/devise_token_auth/pull/302) ([colavitam](https://github.com/colavitam)) +- Fix an issue for not :confirmable users [\#296](https://github.com/lynndylanhurley/devise_token_auth/pull/296) ([sebfie](https://github.com/sebfie)) +- Update README.md [\#295](https://github.com/lynndylanhurley/devise_token_auth/pull/295) ([adisos](https://github.com/adisos)) +- Fix MOUNT\_PATH 'Read More' link [\#294](https://github.com/lynndylanhurley/devise_token_auth/pull/294) ([jmliu](https://github.com/jmliu)) +- Don't send password reset instructions to unconfirmed email [\#288](https://github.com/lynndylanhurley/devise_token_auth/pull/288) ([coryschires](https://github.com/coryschires)) +- Feature/i18n support [\#283](https://github.com/lynndylanhurley/devise_token_auth/pull/283) ([sebfie](https://github.com/sebfie)) +- Update documentation for validate\_token [\#277](https://github.com/lynndylanhurley/devise_token_auth/pull/277) ([adamgall](https://github.com/adamgall)) +- Added json support for tokens [\#276](https://github.com/lynndylanhurley/devise_token_auth/pull/276) ([shicholas](https://github.com/shicholas)) +- perf\(token\_is\_current?\): add simplistic cache to reduce overhead of redundant token checks during validation calls [\#272](https://github.com/lynndylanhurley/devise_token_auth/pull/272) ([booleanbetrayal](https://github.com/booleanbetrayal)) +- perf\(update\_auth\_header\): only lock the resource if we are rotating tokens [\#267](https://github.com/lynndylanhurley/devise_token_auth/pull/267) ([booleanbetrayal](https://github.com/booleanbetrayal)) +- fix\(email-validation\): Update in-use email validation message during registration to allow full\_message use [\#255](https://github.com/lynndylanhurley/devise_token_auth/pull/255) ([booleanbetrayal](https://github.com/booleanbetrayal)) +- fix\(session\#new\): fix unhandled 500 when logging in with valid user and bad password [\#254](https://github.com/lynndylanhurley/devise_token_auth/pull/254) ([mathemagica](https://github.com/mathemagica)) +- feat\(ominauth\): support json-formatted values in omniauth callback. [\#252](https://github.com/lynndylanhurley/devise_token_auth/pull/252) ([nbrustein](https://github.com/nbrustein)) +- fix\(sessions controller\): call reset\_session on destroy [\#251](https://github.com/lynndylanhurley/devise_token_auth/pull/251) ([nbrustein](https://github.com/nbrustein)) +- fix\(resource\_class\): support optional mapping property from set\_user\_by\_token [\#250](https://github.com/lynndylanhurley/devise_token_auth/pull/250) ([booleanbetrayal](https://github.com/booleanbetrayal)) +- Allow current\_password to be supplied when updating profile. [\#240](https://github.com/lynndylanhurley/devise_token_auth/pull/240) ([jasonswett](https://github.com/jasonswett)) +- fixes password reset when not using confirmable [\#225](https://github.com/lynndylanhurley/devise_token_auth/pull/225) ([aesnyder](https://github.com/aesnyder)) +- Fix error when email missing from registration params [\#220](https://github.com/lynndylanhurley/devise_token_auth/pull/220) ([iangreenleaf](https://github.com/iangreenleaf)) +- URI fragment should appear at the end of URL [\#214](https://github.com/lynndylanhurley/devise_token_auth/pull/214) ([edymerchk](https://github.com/edymerchk)) +- Super block yield \(all controllers\) [\#209](https://github.com/lynndylanhurley/devise_token_auth/pull/209) ([sgwilym](https://github.com/sgwilym)) +- Super block yield [\#207](https://github.com/lynndylanhurley/devise_token_auth/pull/207) ([sgwilym](https://github.com/sgwilym)) +- Ability to localize error message [\#206](https://github.com/lynndylanhurley/devise_token_auth/pull/206) ([lda](https://github.com/lda)) +- remove fragment sign \("\#"\) from URLs without fragment [\#205](https://github.com/lynndylanhurley/devise_token_auth/pull/205) ([tomdov](https://github.com/tomdov)) +- Return 422 \(was 500\) when empty body for sign up and account update [\#204](https://github.com/lynndylanhurley/devise_token_auth/pull/204) ([mchavarriagam](https://github.com/mchavarriagam)) +- Users with allowed unconfirmed access can now log in successfully. [\#202](https://github.com/lynndylanhurley/devise_token_auth/pull/202) ([colavitam](https://github.com/colavitam)) +- Authenticating an existing Warden/Devise User [\#200](https://github.com/lynndylanhurley/devise_token_auth/pull/200) ([nickL](https://github.com/nickL)) +- GET sign\_in should direct people to use POST sign\_in rather than raising exception [\#191](https://github.com/lynndylanhurley/devise_token_auth/pull/191) ([milesmatthias](https://github.com/milesmatthias)) +- Ignore 'extra' in Twitter auth response to avoid CookieOverflow. Fixes \#145. [\#179](https://github.com/lynndylanhurley/devise_token_auth/pull/179) ([tbloncar](https://github.com/tbloncar)) +- Some missing as\_json ? [\#152](https://github.com/lynndylanhurley/devise_token_auth/pull/152) ([nicolas-besnard](https://github.com/nicolas-besnard)) +- Check email format on registration [\#150](https://github.com/lynndylanhurley/devise_token_auth/pull/150) ([nicolas-besnard](https://github.com/nicolas-besnard)) +- Actual header key uses dashes, not underscores. [\#143](https://github.com/lynndylanhurley/devise_token_auth/pull/143) ([ragaskar](https://github.com/ragaskar)) +- Username register login [\#128](https://github.com/lynndylanhurley/devise_token_auth/pull/128) ([nicolas-besnard](https://github.com/nicolas-besnard)) +- Check if confirmable is active before skipping confirmation [\#125](https://github.com/lynndylanhurley/devise_token_auth/pull/125) ([nicolas-besnard](https://github.com/nicolas-besnard)) +- Fix links to section about controller integration. [\#117](https://github.com/lynndylanhurley/devise_token_auth/pull/117) ([Le6ow5k1](https://github.com/Le6ow5k1)) +- document GET for /validate\_token [\#113](https://github.com/lynndylanhurley/devise_token_auth/pull/113) ([lukaselmer](https://github.com/lukaselmer)) +- Fix small error in documentation. [\#91](https://github.com/lynndylanhurley/devise_token_auth/pull/91) ([edgarhenriquez](https://github.com/edgarhenriquez)) +- Exclude devise modules [\#85](https://github.com/lynndylanhurley/devise_token_auth/pull/85) ([jartek](https://github.com/jartek)) +- fix\(registration and update\): Ensure UID is updated alongside Email, and case-sensitivity is honored [\#71](https://github.com/lynndylanhurley/devise_token_auth/pull/71) ([booleanbetrayal](https://github.com/booleanbetrayal)) +- Add better guidelines for contributors. [\#67](https://github.com/lynndylanhurley/devise_token_auth/pull/67) ([edgarhenriquez](https://github.com/edgarhenriquez)) +- Use resource\_class to override email confirmation. [\#64](https://github.com/lynndylanhurley/devise_token_auth/pull/64) ([edgarhenriquez](https://github.com/edgarhenriquez)) +- fix\(case-sensitivity\): support devise case\_insensitive\_keys for session ... [\#57](https://github.com/lynndylanhurley/devise_token_auth/pull/57) ([booleanbetrayal](https://github.com/booleanbetrayal)) +- fix\(contention\): fix write contention in update\_auth\_headers and always ... [\#52](https://github.com/lynndylanhurley/devise_token_auth/pull/52) ([booleanbetrayal](https://github.com/booleanbetrayal)) +- Include resource.errors.full\_messages in error response. [\#50](https://github.com/lynndylanhurley/devise_token_auth/pull/50) ([jasonswett](https://github.com/jasonswett)) +- fix\(expiry\): fix an issue where token expiration checks were too permissive [\#49](https://github.com/lynndylanhurley/devise_token_auth/pull/49) ([booleanbetrayal](https://github.com/booleanbetrayal)) +- Update README with Example Generator Command [\#35](https://github.com/lynndylanhurley/devise_token_auth/pull/35) ([wwilkins](https://github.com/wwilkins)) +- Remove OmniAuth dependency [\#26](https://github.com/lynndylanhurley/devise_token_auth/pull/26) ([hannahhoward](https://github.com/hannahhoward)) +- Update README.md [\#24](https://github.com/lynndylanhurley/devise_token_auth/pull/24) ([davidsavoya](https://github.com/davidsavoya)) +- guard against MissingAttributeError during common ActiveRecord operations [\#19](https://github.com/lynndylanhurley/devise_token_auth/pull/19) ([booleanbetrayal](https://github.com/booleanbetrayal)) +- Fix expiry data type [\#11](https://github.com/lynndylanhurley/devise_token_auth/pull/11) ([lonre](https://github.com/lonre)) +- README and travis config tweaks [\#7](https://github.com/lynndylanhurley/devise_token_auth/pull/7) ([guilhermesimoes](https://github.com/guilhermesimoes)) + +# Change Log + +## [v0.1.40](https://github.com/lynndylanhurley/devise_token_auth/tree/v0.1.40) (2017-01-20) +[Full Changelog](https://github.com/lynndylanhurley/devise_token_auth/compare/v0.1.39...v0.1.40) + + +**Closed issues:** + +- Support for multiple providers during same session [\#815](https://github.com/lynndylanhurley/devise_token_auth/issues/815) +- not supporting for angular1.6 [\#810](https://github.com/lynndylanhurley/devise_token_auth/issues/810) +- Add has one/belongs to assotiation [\#807](https://github.com/lynndylanhurley/devise_token_auth/issues/807) +- redirect\_url required but not permitted in strong parameters [\#805](https://github.com/lynndylanhurley/devise_token_auth/issues/805) +- Rails 5 API Mode Not Authorizing [\#796](https://github.com/lynndylanhurley/devise_token_auth/issues/796) +- wrong constant name user [\#784](https://github.com/lynndylanhurley/devise_token_auth/issues/784) +- current\_user returns nill [\#779](https://github.com/lynndylanhurley/devise_token_auth/issues/779) +- ActionController::RoutingError - undefined method `helper\_method' [\#776](https://github.com/lynndylanhurley/devise_token_auth/issues/776) +- Minimum Limits on a token? [\#764](https://github.com/lynndylanhurley/devise_token_auth/issues/764) +- Octopus throwing error when deleting expired tokens [\#761](https://github.com/lynndylanhurley/devise_token_auth/issues/761) +- Only one User model return the correct headers [\#757](https://github.com/lynndylanhurley/devise_token_auth/issues/757) +- ArgumentError in Devise::RegistrationsController\#new [\#750](https://github.com/lynndylanhurley/devise_token_auth/issues/750) +- Rails 5 API deployed as microservices [\#741](https://github.com/lynndylanhurley/devise_token_auth/issues/741) +- Query params left in url after facebook login cause authentication to fail on refresh [\#734](https://github.com/lynndylanhurley/devise_token_auth/issues/734) +- Can't permit parameters in rails engine [\#731](https://github.com/lynndylanhurley/devise_token_auth/issues/731) +- Cannot integrate with omniauth-facebook [\#729](https://github.com/lynndylanhurley/devise_token_auth/issues/729) +- Two models, one not working [\#726](https://github.com/lynndylanhurley/devise_token_auth/issues/726) +- API response bodies are empty when using active\_model\_serializers [\#715](https://github.com/lynndylanhurley/devise_token_auth/issues/715) +- /sign\_out route is returning 404 not found [\#713](https://github.com/lynndylanhurley/devise_token_auth/issues/713) +- Why is `tokens` field a json type and how to create a query based on inside values? [\#707](https://github.com/lynndylanhurley/devise_token_auth/issues/707) +- Deprecation Error Message on 5.0 [\#698](https://github.com/lynndylanhurley/devise_token_auth/issues/698) + + +**Merged pull requests:** + +- Update german translation. [\#816](https://github.com/lynndylanhurley/devise_token_auth/pull/816) ([gobijan](https://github.com/gobijan)) +- Add support for italian locale [\#811](https://github.com/lynndylanhurley/devise_token_auth/pull/811) ([Chosko](https://github.com/Chosko)) +- Fix privacy issue with password reset request [\#808](https://github.com/lynndylanhurley/devise_token_auth/pull/808) ([biomancer](https://github.com/biomancer)) +- Add missing parameter :redirect\_url, fixes \#805 [\#806](https://github.com/lynndylanhurley/devise_token_auth/pull/806) ([Rush](https://github.com/Rush)) +- Fix language errors in German locale [\#800](https://github.com/lynndylanhurley/devise_token_auth/pull/800) ([morgler](https://github.com/morgler)) +- Don't send extra data on request password reset [\#798](https://github.com/lynndylanhurley/devise_token_auth/pull/798) ([Mrjaco12](https://github.com/Mrjaco12)) +- Travis: use the code\_climate addon config [\#786](https://github.com/lynndylanhurley/devise_token_auth/pull/786) ([olleolleolle](https://github.com/olleolleolle)) +- Update link [\#782](https://github.com/lynndylanhurley/devise_token_auth/pull/782) ([dijonkitchen](https://github.com/dijonkitchen)) +- Add index for confirmation\_token [\#767](https://github.com/lynndylanhurley/devise_token_auth/pull/767) ([dijonkitchen](https://github.com/dijonkitchen)) +- Fixes constructing redirect\_route [\#765](https://github.com/lynndylanhurley/devise_token_auth/pull/765) ([piotrkaczmarek](https://github.com/piotrkaczmarek)) +- Use standart ActiveRecord error message for email uniqueness validation [\#746](https://github.com/lynndylanhurley/devise_token_auth/pull/746) ([mpugach](https://github.com/mpugach)) +- Add Romanian locale. [\#743](https://github.com/lynndylanhurley/devise_token_auth/pull/743) ([razvanmitre](https://github.com/razvanmitre)) +- Update indexes on template [\#724](https://github.com/lynndylanhurley/devise_token_auth/pull/724) ([dijonkitchen](https://github.com/dijonkitchen)) +- Add an extra line to the "contributing" list [\#720](https://github.com/lynndylanhurley/devise_token_auth/pull/720) ([jahammo2](https://github.com/jahammo2)) +- Fix grammar [\#712](https://github.com/lynndylanhurley/devise_token_auth/pull/712) ([dijonkitchen](https://github.com/dijonkitchen)) +- Added reference to Angular2-Token to README [\#710](https://github.com/lynndylanhurley/devise_token_auth/pull/710) ([neroniaky](https://github.com/neroniaky)) +- feat\(whitelist\): add wildcard support for redirect\_whitelist patterns [\#709](https://github.com/lynndylanhurley/devise_token_auth/pull/709) ([booleanbetrayal](https://github.com/booleanbetrayal)) + +# Change Log + +## [v0.1.39](https://github.com/lynndylanhurley/devise_token_auth/tree/v0.1.39) (2016-08-16) +[Full Changelog](https://github.com/lynndylanhurley/devise_token_auth/compare/v0.1.38...v0.1.39) + +**Closed issues:** + +- "Covert Redirect" Vulnerability [\#696](https://github.com/lynndylanhurley/devise_token_auth/issues/696) +- No route matches \[POST\] "/api/v1/auth" [\#694](https://github.com/lynndylanhurley/devise_token_auth/issues/694) +- Got this error with ActiveAdmin "wrong number of arguments \(1 for 0\)" [\#692](https://github.com/lynndylanhurley/devise_token_auth/issues/692) +- using devise\_token\_auth for API alongside standard devise gem for HTML view [\#689](https://github.com/lynndylanhurley/devise_token_auth/issues/689) +- No Headers after sign\_in for new Users created by Admin [\#685](https://github.com/lynndylanhurley/devise_token_auth/issues/685) +- NoMethodError \(undefined method `headers\_names' for DeviseTokenAuth:Module\) [\#684](https://github.com/lynndylanhurley/devise_token_auth/issues/684) +- Fast page refresh problem [\#683](https://github.com/lynndylanhurley/devise_token_auth/issues/683) +- IndexError: string not matched on User sign\_in [\#681](https://github.com/lynndylanhurley/devise_token_auth/issues/681) +- skip\_confirmation\_notification! not working [\#679](https://github.com/lynndylanhurley/devise_token_auth/issues/679) +- Bump version to support devise 4.1.1 [\#659](https://github.com/lynndylanhurley/devise_token_auth/issues/659) +- not working with latest version of active\_model\_serializers [\#600](https://github.com/lynndylanhurley/devise_token_auth/issues/600) + +**Merged pull requests:** + +- Fix Migration Deprecation Warning [\#700](https://github.com/lynndylanhurley/devise_token_auth/pull/700) ([juddey](https://github.com/juddey)) +- Apply `redirect\_whitelist` to OAuth redirect URI. [\#699](https://github.com/lynndylanhurley/devise_token_auth/pull/699) ([lynndylanhurley](https://github.com/lynndylanhurley)) +- add zh-CN.yml [\#697](https://github.com/lynndylanhurley/devise_token_auth/pull/697) ([halfray](https://github.com/halfray)) +- update README.md [\#693](https://github.com/lynndylanhurley/devise_token_auth/pull/693) ([nhattan](https://github.com/nhattan)) + +## [0.1.38](https://github.com/lynndylanhurley/devise_token_auth/tree/HEAD) + +[Full Changelog](https://github.com/lynndylanhurley/devise_token_auth/compare/v0.1.37...HEAD) + +**Implemented enhancements:** + +- Rails generator to update views [\#33](https://github.com/lynndylanhurley/devise_token_auth/issues/33) +- Extract Omniauth attributes assignation into a method [\#31](https://github.com/lynndylanhurley/devise_token_auth/issues/31) + +**Fixed bugs:** + +- Generator doesn't work correctly with mongoid and/or rails-api [\#14](https://github.com/lynndylanhurley/devise_token_auth/issues/14) +- Generator issues [\#13](https://github.com/lynndylanhurley/devise_token_auth/issues/13) + +**Closed issues:** + +- rails g devise\_token\_auth:install User auth hangs and does nothing [\#671](https://github.com/lynndylanhurley/devise_token_auth/issues/671) +- callback :set\_user\_by\_token has not been defined [\#649](https://github.com/lynndylanhurley/devise_token_auth/issues/649) +- Issues with active\_model\_serializers [\#644](https://github.com/lynndylanhurley/devise_token_auth/issues/644) +- Error with devise [\#643](https://github.com/lynndylanhurley/devise_token_auth/issues/643) +- undefined method `token\_validation\_response' [\#635](https://github.com/lynndylanhurley/devise_token_auth/issues/635) +- when password is reset from UI, all tokens must be removed if remove\_tokens\_after\_password\_reset is true [\#634](https://github.com/lynndylanhurley/devise_token_auth/issues/634) +- Relax devise dependency to allow 4.1 [\#631](https://github.com/lynndylanhurley/devise_token_auth/issues/631) +- Rails 5 generator doesn't insert concern [\#627](https://github.com/lynndylanhurley/devise_token_auth/issues/627) +- NoMethodError \(undefined method `find\_by\_uid'\) in production. [\#625](https://github.com/lynndylanhurley/devise_token_auth/issues/625) +- Curl not working for sign\_in but works on ng-token-angular [\#620](https://github.com/lynndylanhurley/devise_token_auth/issues/620) +- After Sign-in success, The following requests on Angular side are unauthorized. [\#619](https://github.com/lynndylanhurley/devise_token_auth/issues/619) +- Omniauth - Facebook app doesn't run callback url after successful Facebook authentication [\#615](https://github.com/lynndylanhurley/devise_token_auth/issues/615) +- :authenticate\_user! wired behaviour [\#614](https://github.com/lynndylanhurley/devise_token_auth/issues/614) +- current\_user is nil, request headers are all upcased and prefixed with HTML\_ [\#611](https://github.com/lynndylanhurley/devise_token_auth/issues/611) +- Problem in generated routes [\#607](https://github.com/lynndylanhurley/devise_token_auth/issues/607) +- Rails 5 API Mode - no headers in response [\#606](https://github.com/lynndylanhurley/devise_token_auth/issues/606) +- Filter chain halted as :authenticate\_user! rendered or redirected [\#603](https://github.com/lynndylanhurley/devise_token_auth/issues/603) +- 422 Unprocessable Entity when using local IP address [\#601](https://github.com/lynndylanhurley/devise_token_auth/issues/601) +- overriding rendering methods in devise\_token\_auth [\#597](https://github.com/lynndylanhurley/devise_token_auth/issues/597) +- redirect\_url is missing in email instructions sent to the user for password reset [\#588](https://github.com/lynndylanhurley/devise_token_auth/issues/588) +- Unpermitted parameter: {"email":"mail@gmail.com","password":"abcdefgh","password\_confirmation":"abcdefgh"} [\#587](https://github.com/lynndylanhurley/devise_token_auth/issues/587) +- can't authenticate user when opening a new download tab [\#582](https://github.com/lynndylanhurley/devise_token_auth/issues/582) +- Mails are not being sent [\#581](https://github.com/lynndylanhurley/devise_token_auth/issues/581) +- current\_user seems to be nil after doing requests from different tabs [\#579](https://github.com/lynndylanhurley/devise_token_auth/issues/579) +- Do we have any rspec helpers to sign\_in an user? [\#577](https://github.com/lynndylanhurley/devise_token_auth/issues/577) +- Cannot override json response of authenticate\_user! [\#575](https://github.com/lynndylanhurley/devise_token_auth/issues/575) +- return custom json data after sign\_in [\#567](https://github.com/lynndylanhurley/devise_token_auth/issues/567) +- /auth/validate\_token works but getting 401 unauthorized when sending request with auth headers [\#550](https://github.com/lynndylanhurley/devise_token_auth/issues/550) +- Where is the access key of omniauth provider? [\#549](https://github.com/lynndylanhurley/devise_token_auth/issues/549) +- How this gem is different from a JWT system? [\#543](https://github.com/lynndylanhurley/devise_token_auth/issues/543) +- Improper formatting for JSON API error/success responses [\#536](https://github.com/lynndylanhurley/devise_token_auth/issues/536) +- Is it a hybrid authentication system? [\#527](https://github.com/lynndylanhurley/devise_token_auth/issues/527) +- check\_current\_password\_before\_update still requires password when resetting password [\#526](https://github.com/lynndylanhurley/devise_token_auth/issues/526) +- Manually authenticate for testing [\#521](https://github.com/lynndylanhurley/devise_token_auth/issues/521) +- Support for STI [\#517](https://github.com/lynndylanhurley/devise_token_auth/issues/517) +- JSON responses don't fit JSON\_API requirements [\#512](https://github.com/lynndylanhurley/devise_token_auth/issues/512) +- Not working with rails 5 and devise master [\#504](https://github.com/lynndylanhurley/devise_token_auth/issues/504) +- Unpermitted parameters: confirm\_success\_url, config\_name, registration [\#501](https://github.com/lynndylanhurley/devise_token_auth/issues/501) +- set\_user\_by\_token not defined in production for rails 5 [\#500](https://github.com/lynndylanhurley/devise_token_auth/issues/500) +- Master branch no longer working with devise master branch \(version error\) [\#498](https://github.com/lynndylanhurley/devise_token_auth/issues/498) +- uid is not getting set in git revision 996b9cf23a18 [\#497](https://github.com/lynndylanhurley/devise_token_auth/issues/497) +- ve\_model\_serializer namespace [\#492](https://github.com/lynndylanhurley/devise_token_auth/issues/492) +- User remains logged in when using devise and devise\_token\_auth in the same app [\#486](https://github.com/lynndylanhurley/devise_token_auth/issues/486) +- DEPRECATION WARNING: alias\_method\_chain is deprecated. Rails 5 [\#482](https://github.com/lynndylanhurley/devise_token_auth/issues/482) +- validate\_token - resource\_name - undefined method `name' for nil:NilClass [\#480](https://github.com/lynndylanhurley/devise_token_auth/issues/480) +- Helpers being loaded for Rails API's [\#468](https://github.com/lynndylanhurley/devise_token_auth/issues/468) +- Unable to call `rails g devise\_token\_auth:install` within rails engine [\#465](https://github.com/lynndylanhurley/devise_token_auth/issues/465) +- locales `errors.messages.already\_in\_use` seems broken [\#463](https://github.com/lynndylanhurley/devise_token_auth/issues/463) +- It shows "An error occurred" after omniauth callback [\#445](https://github.com/lynndylanhurley/devise_token_auth/issues/445) +- - [\#444](https://github.com/lynndylanhurley/devise_token_auth/issues/444) +- Put Access Token in body [\#442](https://github.com/lynndylanhurley/devise_token_auth/issues/442) +- Unable to add a new param for sign up [\#440](https://github.com/lynndylanhurley/devise_token_auth/issues/440) +- Undefined method provider from devise\_toke\_auth concerns/user.rb [\#438](https://github.com/lynndylanhurley/devise_token_auth/issues/438) +- Scoped DeviseToken but it still affects the original Omniauth redirects. [\#429](https://github.com/lynndylanhurley/devise_token_auth/issues/429) +- Can't create user via api [\#422](https://github.com/lynndylanhurley/devise_token_auth/issues/422) +- Password Reset question, do I need my own form? [\#418](https://github.com/lynndylanhurley/devise_token_auth/issues/418) +- Large Size on Disk [\#415](https://github.com/lynndylanhurley/devise_token_auth/issues/415) +- The validate\_token function in the readme is missing a parameter [\#413](https://github.com/lynndylanhurley/devise_token_auth/issues/413) +- Cannot migrate database: NoMethodError: undefined method `new' for DeviseTokenAuth:Module [\#406](https://github.com/lynndylanhurley/devise_token_auth/issues/406) +- change\_headers\_on\_each\_request and batch requests [\#403](https://github.com/lynndylanhurley/devise_token_auth/issues/403) +- Multiple users, returning\(and creating\) wrong model's auth token [\#399](https://github.com/lynndylanhurley/devise_token_auth/issues/399) +- Can't verify CSRF token authenticity [\#398](https://github.com/lynndylanhurley/devise_token_auth/issues/398) +- uninitialized constant DeviseTokenAuth::OmniauthCallbacksController::BCrypt [\#393](https://github.com/lynndylanhurley/devise_token_auth/issues/393) +- Sign in not success. [\#388](https://github.com/lynndylanhurley/devise_token_auth/issues/388) +- password length [\#380](https://github.com/lynndylanhurley/devise_token_auth/issues/380) +- Devise token auth not found routing error [\#379](https://github.com/lynndylanhurley/devise_token_auth/issues/379) +- Defining a custom primary key [\#378](https://github.com/lynndylanhurley/devise_token_auth/issues/378) +- seeing other users data after login/out with different users on ionic [\#375](https://github.com/lynndylanhurley/devise_token_auth/issues/375) +- omniauth: when redirecting, user object should not be serialized into url [\#368](https://github.com/lynndylanhurley/devise_token_auth/issues/368) +- getting ng-token-auth and devise\_token\_auth to work with OAuth in ionic InAppBrowser [\#367](https://github.com/lynndylanhurley/devise_token_auth/issues/367) +- omniauth callback redirect not working properly when using namespace/scope [\#362](https://github.com/lynndylanhurley/devise_token_auth/issues/362) +- invalid token in method set\_user\_by\_token on RegistrationsController\#update [\#357](https://github.com/lynndylanhurley/devise_token_auth/issues/357) +- Allow devise patch version updates [\#351](https://github.com/lynndylanhurley/devise_token_auth/issues/351) +- Error validating token [\#348](https://github.com/lynndylanhurley/devise_token_auth/issues/348) +- Allow for HTTP Basic Auth ? [\#337](https://github.com/lynndylanhurley/devise_token_auth/issues/337) +- Allow Omniauth user reset password [\#335](https://github.com/lynndylanhurley/devise_token_auth/issues/335) +- NameError \(uninitialized constant DeviseTokenAuth::Concerns::User::BCrypt\) [\#333](https://github.com/lynndylanhurley/devise_token_auth/issues/333) +- Unpermitted parameters: format, session [\#328](https://github.com/lynndylanhurley/devise_token_auth/issues/328) +- devise token auth + Save Facebook auth\_hash info in database [\#326](https://github.com/lynndylanhurley/devise_token_auth/issues/326) +- Error sending password reset email when not using confirmable \(reopened \#124\) [\#321](https://github.com/lynndylanhurley/devise_token_auth/issues/321) +- Routing error / Preflight request / OPTIONS [\#320](https://github.com/lynndylanhurley/devise_token_auth/issues/320) +- delete tokens after password change [\#318](https://github.com/lynndylanhurley/devise_token_auth/issues/318) +- Can't authorize \(user\_signed\_in? always show false\) [\#315](https://github.com/lynndylanhurley/devise_token_auth/issues/315) +- Warden::SessionSerializer - wrong number of arguments \(2 for 1\) [\#312](https://github.com/lynndylanhurley/devise_token_auth/issues/312) +- The action 'twitter' could not be found for DeviseTokenAuth::OmniauthCallbacksController [\#309](https://github.com/lynndylanhurley/devise_token_auth/issues/309) +- Having 401 Unauthorized only with mobile [\#305](https://github.com/lynndylanhurley/devise_token_auth/issues/305) +- remove unused nickname, image from user object [\#304](https://github.com/lynndylanhurley/devise_token_auth/issues/304) +- HI, This is more of a doubt since I could not finding anything related to this in your documentation. [\#300](https://github.com/lynndylanhurley/devise_token_auth/issues/300) +- Getting 401's when making requests using iOS/Android clients [\#299](https://github.com/lynndylanhurley/devise_token_auth/issues/299) +- undefined method `tokens' for \#\ [\#297](https://github.com/lynndylanhurley/devise_token_auth/issues/297) +- Confirmation URL giving bad arguments [\#293](https://github.com/lynndylanhurley/devise_token_auth/issues/293) +- set\_user\_by\_token not called in overriden controller [\#291](https://github.com/lynndylanhurley/devise_token_auth/issues/291) +- Question: Should we send password reset instructions to unconfirmed emails? [\#287](https://github.com/lynndylanhurley/devise_token_auth/issues/287) +- NoMethodError \(undefined method `\[\]' for nil:NilClass\): [\#286](https://github.com/lynndylanhurley/devise_token_auth/issues/286) +- Facebook omniauth redirection is missing url when testing on localhost [\#285](https://github.com/lynndylanhurley/devise_token_auth/issues/285) +- No route matches \[GET\] "/users/facebook/callback" [\#280](https://github.com/lynndylanhurley/devise_token_auth/issues/280) +- No route matches \[GET\] "/omniauth/:provider" [\#278](https://github.com/lynndylanhurley/devise_token_auth/issues/278) +- How to refresh token/expiry? [\#275](https://github.com/lynndylanhurley/devise_token_auth/issues/275) +- wrong number of arguments \(1 for 0\): in DeviseTokenAuth::RegistrationsController\#create [\#274](https://github.com/lynndylanhurley/devise_token_auth/issues/274) +- Can not save a user with nil tokens attribute [\#271](https://github.com/lynndylanhurley/devise_token_auth/issues/271) +- Shouldn't validate\_token param be access-token, not auth\_token? [\#270](https://github.com/lynndylanhurley/devise_token_auth/issues/270) +- include associations on login [\#269](https://github.com/lynndylanhurley/devise_token_auth/issues/269) +- Failure route not handled [\#262](https://github.com/lynndylanhurley/devise_token_auth/issues/262) +- Getting Unauthorized error even after sending the correct token, uid and client [\#261](https://github.com/lynndylanhurley/devise_token_auth/issues/261) +- Weird error message [\#259](https://github.com/lynndylanhurley/devise_token_auth/issues/259) +- undefined method `provider' for \#\ [\#257](https://github.com/lynndylanhurley/devise_token_auth/issues/257) +- Custom Serializer like ActiveModel Serializer [\#249](https://github.com/lynndylanhurley/devise_token_auth/issues/249) +- File download with query params [\#246](https://github.com/lynndylanhurley/devise_token_auth/issues/246) +- Info: is devise\_token\_auth compatible with rails 3.2.19? [\#245](https://github.com/lynndylanhurley/devise_token_auth/issues/245) +- Headers required for different methods [\#243](https://github.com/lynndylanhurley/devise_token_auth/issues/243) +- Unpermitted parameters: format, session, lang [\#239](https://github.com/lynndylanhurley/devise_token_auth/issues/239) +- On sign\_in, devise\_token\_auth expects the uid to be the same as the email [\#237](https://github.com/lynndylanhurley/devise_token_auth/issues/237) +- Name conflict with inherited\_resources [\#236](https://github.com/lynndylanhurley/devise_token_auth/issues/236) +- sign\_in will not fetch the token [\#234](https://github.com/lynndylanhurley/devise_token_auth/issues/234) +- Remove \('\#'\) symbol when using html5mode in locationProvider [\#232](https://github.com/lynndylanhurley/devise_token_auth/issues/232) +- Log in request 401 error [\#231](https://github.com/lynndylanhurley/devise_token_auth/issues/231) +- User Registration - "email address already in use" when it is unique [\#230](https://github.com/lynndylanhurley/devise_token_auth/issues/230) +- Devise email validation disabled...why? [\#229](https://github.com/lynndylanhurley/devise_token_auth/issues/229) +- confirm\_success\_url error not working [\#226](https://github.com/lynndylanhurley/devise_token_auth/issues/226) +- pending\_reconfirmation called when confirmable isn't used [\#224](https://github.com/lynndylanhurley/devise_token_auth/issues/224) +- omniauth\_success.html.erb JSON bug [\#221](https://github.com/lynndylanhurley/devise_token_auth/issues/221) +- Using devise\_token\_auth and ng\_token\_auth with angularJS in an Ionic Hybrid application [\#218](https://github.com/lynndylanhurley/devise_token_auth/issues/218) +- Where can I got token? [\#217](https://github.com/lynndylanhurley/devise_token_auth/issues/217) +- URI fragment prevent to send params in Confirmation URL [\#213](https://github.com/lynndylanhurley/devise_token_auth/issues/213) +- Generating many client tokens [\#210](https://github.com/lynndylanhurley/devise_token_auth/issues/210) +- Limit tokens hash? [\#208](https://github.com/lynndylanhurley/devise_token_auth/issues/208) +- 500 error returned when no data is POSTed to registration controller [\#203](https://github.com/lynndylanhurley/devise_token_auth/issues/203) +- undefined method `match' for nil:NilClass [\#201](https://github.com/lynndylanhurley/devise_token_auth/issues/201) +- DELETE method becoming OPTIONS @ Heroku [\#197](https://github.com/lynndylanhurley/devise_token_auth/issues/197) +- 40 Mb log file and 1 minute to have token with curl [\#195](https://github.com/lynndylanhurley/devise_token_auth/issues/195) +- 401 unauthorized [\#193](https://github.com/lynndylanhurley/devise_token_auth/issues/193) +- GET requests to sign\_in shouldn't raise an exception [\#190](https://github.com/lynndylanhurley/devise_token_auth/issues/190) +- Api not locked by default [\#189](https://github.com/lynndylanhurley/devise_token_auth/issues/189) +- Rails 4.1 [\#187](https://github.com/lynndylanhurley/devise_token_auth/issues/187) +- Unable to override OmniauthCallbacksController\#redirect\_callbacks [\#186](https://github.com/lynndylanhurley/devise_token_auth/issues/186) +- Token based authentication with no sessions [\#183](https://github.com/lynndylanhurley/devise_token_auth/issues/183) +- undefined method `authenticate\_user!' [\#182](https://github.com/lynndylanhurley/devise_token_auth/issues/182) +- confirm\_success\_url shouldn't be a required param [\#176](https://github.com/lynndylanhurley/devise_token_auth/issues/176) +- Provide an OAuth implementation for native apps [\#175](https://github.com/lynndylanhurley/devise_token_auth/issues/175) +- getting an argument error when trying to use omniauth [\#174](https://github.com/lynndylanhurley/devise_token_auth/issues/174) +- Sign in via username doesn't seem to work correctly. [\#173](https://github.com/lynndylanhurley/devise_token_auth/issues/173) +- Cannot use + sign in email address. [\#171](https://github.com/lynndylanhurley/devise_token_auth/issues/171) +- How can i authenticate using curl and get private entries ! [\#167](https://github.com/lynndylanhurley/devise_token_auth/issues/167) +- Pessimistic Locking produces ArgumentError [\#165](https://github.com/lynndylanhurley/devise_token_auth/issues/165) +- POTENTIAL SECURITY RISK: Setting confirm\_success\_url and redirect\_url via API [\#162](https://github.com/lynndylanhurley/devise_token_auth/issues/162) +- Sign out just on client side ? [\#161](https://github.com/lynndylanhurley/devise_token_auth/issues/161) +- Unpermitted parameter: redirect\_url [\#160](https://github.com/lynndylanhurley/devise_token_auth/issues/160) +- Issues using devise and devise\_token\_auth [\#159](https://github.com/lynndylanhurley/devise_token_auth/issues/159) +- Add role based authorization [\#158](https://github.com/lynndylanhurley/devise_token_auth/issues/158) +- Not compatible with ActiveAdmin [\#156](https://github.com/lynndylanhurley/devise_token_auth/issues/156) +- \[Duplicate\] is devise\_invitable supported? [\#154](https://github.com/lynndylanhurley/devise_token_auth/issues/154) +- User can register with a "false" email [\#149](https://github.com/lynndylanhurley/devise_token_auth/issues/149) +- /validate\_token [\#148](https://github.com/lynndylanhurley/devise_token_auth/issues/148) +- Email confirmation link [\#147](https://github.com/lynndylanhurley/devise_token_auth/issues/147) +- Tokens field on database [\#146](https://github.com/lynndylanhurley/devise_token_auth/issues/146) +- Twitter OAuth always throughs CookieOverflow [\#145](https://github.com/lynndylanhurley/devise_token_auth/issues/145) +- Is there a way to configure apiUrl for both dev and prod? [\#144](https://github.com/lynndylanhurley/devise_token_auth/issues/144) +- Getting 401 unauthorized on login attempt [\#142](https://github.com/lynndylanhurley/devise_token_auth/issues/142) +- Comparing with jwt [\#140](https://github.com/lynndylanhurley/devise_token_auth/issues/140) +- Can't get omniauth to work \(error in redirect\_callbacks\) [\#139](https://github.com/lynndylanhurley/devise_token_auth/issues/139) +- Change controller inheritance [\#138](https://github.com/lynndylanhurley/devise_token_auth/issues/138) +- Reset Password call returns 400 for Not Found user [\#137](https://github.com/lynndylanhurley/devise_token_auth/issues/137) +- The gem is too big. Please take care of it. [\#136](https://github.com/lynndylanhurley/devise_token_auth/issues/136) +- Error when loging with facebook the second time without logout [\#135](https://github.com/lynndylanhurley/devise_token_auth/issues/135) +- OmniAuth redirect doesn't work if using the generated mount\_devise\_token route [\#133](https://github.com/lynndylanhurley/devise_token_auth/issues/133) +- Missing template /omniauth\_response [\#132](https://github.com/lynndylanhurley/devise_token_auth/issues/132) +- Unpermitted parameter: session [\#130](https://github.com/lynndylanhurley/devise_token_auth/issues/130) +- OAuth error: We're sorry, but something went wrong [\#129](https://github.com/lynndylanhurley/devise_token_auth/issues/129) +- Would it be useful to integrate login with username ? [\#127](https://github.com/lynndylanhurley/devise_token_auth/issues/127) +- Sign in with login instead of email [\#126](https://github.com/lynndylanhurley/devise_token_auth/issues/126) +- Error sending password reset email when not using confirmable [\#124](https://github.com/lynndylanhurley/devise_token_auth/issues/124) +- Using expired token for parallel calls [\#123](https://github.com/lynndylanhurley/devise_token_auth/issues/123) +- User tokens don't properly deserialize [\#121](https://github.com/lynndylanhurley/devise_token_auth/issues/121) +- Could not load 'omniauth' [\#118](https://github.com/lynndylanhurley/devise_token_auth/issues/118) +- bad argument \(expected URI object or URI string\) [\#116](https://github.com/lynndylanhurley/devise_token_auth/issues/116) +- devise\_token\_auth for public API, but devise for rest of app? [\#114](https://github.com/lynndylanhurley/devise_token_auth/issues/114) +- Omniauthable deleted on UsersConcern : Why ? [\#111](https://github.com/lynndylanhurley/devise_token_auth/issues/111) +- Unrequired route [\#110](https://github.com/lynndylanhurley/devise_token_auth/issues/110) +- raises NoMethodError instead of displaying error when email is missing [\#108](https://github.com/lynndylanhurley/devise_token_auth/issues/108) +- Error with RailsAdmin. "The action 'new' could not be found for DeviseTokenAuth::SessionsController" [\#107](https://github.com/lynndylanhurley/devise_token_auth/issues/107) +- Circular dependency detected while autoloading constant Api [\#106](https://github.com/lynndylanhurley/devise_token_auth/issues/106) +- Can't Authenticate via cURL [\#105](https://github.com/lynndylanhurley/devise_token_auth/issues/105) +- Unpermitted parameters: user, registration [\#104](https://github.com/lynndylanhurley/devise_token_auth/issues/104) +- BCrypt::Errors::InvalidSalt errors [\#103](https://github.com/lynndylanhurley/devise_token_auth/issues/103) +- Active job token expiring integration [\#102](https://github.com/lynndylanhurley/devise_token_auth/issues/102) +- The action 'new' could not be found for DeviseTokenAuth::RegistrationsController [\#100](https://github.com/lynndylanhurley/devise_token_auth/issues/100) +- Disable confirmable [\#99](https://github.com/lynndylanhurley/devise_token_auth/issues/99) +- responders - rails 4.2 [\#98](https://github.com/lynndylanhurley/devise_token_auth/issues/98) +- forward skip to devise [\#97](https://github.com/lynndylanhurley/devise_token_auth/issues/97) +- API versioning the devise scope of token validation and ominiauth controller path will wrap up [\#96](https://github.com/lynndylanhurley/devise_token_auth/issues/96) +- Overwriting default "from" email address [\#94](https://github.com/lynndylanhurley/devise_token_auth/issues/94) +- uninitialized constant DeviseTokenAuth [\#92](https://github.com/lynndylanhurley/devise_token_auth/issues/92) +- change\_headers\_on\_each\_request not working expiry header empty [\#90](https://github.com/lynndylanhurley/devise_token_auth/issues/90) +- Gem render consistency [\#87](https://github.com/lynndylanhurley/devise_token_auth/issues/87) +- Sample Sessions Controller for logging in via Rails View. [\#86](https://github.com/lynndylanhurley/devise_token_auth/issues/86) +- Change authorization key: Use phone\_number instead of email [\#84](https://github.com/lynndylanhurley/devise_token_auth/issues/84) +- Conflict with active\_admin gem [\#83](https://github.com/lynndylanhurley/devise_token_auth/issues/83) +- NoMethodError in DeviseTokenAuth::OmniauthCallbacksController\#redirect\_callbacks [\#82](https://github.com/lynndylanhurley/devise_token_auth/issues/82) +- All the APIs are getting 'Authorized users only' [\#81](https://github.com/lynndylanhurley/devise_token_auth/issues/81) +- Is Devise option Rememberable required ? [\#80](https://github.com/lynndylanhurley/devise_token_auth/issues/80) +- Problem with skip\_confirmation! [\#78](https://github.com/lynndylanhurley/devise_token_auth/issues/78) +- Cannot reset password if registered by omniauth [\#77](https://github.com/lynndylanhurley/devise_token_auth/issues/77) +- NoMethodError at /omniauth/facebook/callback - undefined method `\[\]' for nil:NilClass [\#76](https://github.com/lynndylanhurley/devise_token_auth/issues/76) +- Remove dependency on ActiveRecord [\#72](https://github.com/lynndylanhurley/devise_token_auth/issues/72) +- Skipping Registrations Controller Altogether [\#70](https://github.com/lynndylanhurley/devise_token_auth/issues/70) +- Problem in validate\_token if the model is in a namespace [\#69](https://github.com/lynndylanhurley/devise_token_auth/issues/69) +- Cannot send confirmation email if there is no 'User' model [\#68](https://github.com/lynndylanhurley/devise_token_auth/issues/68) +- Better guidelines for contributors [\#65](https://github.com/lynndylanhurley/devise_token_auth/issues/65) +- admin namespace [\#63](https://github.com/lynndylanhurley/devise_token_auth/issues/63) +- Devise trackable module not working [\#62](https://github.com/lynndylanhurley/devise_token_auth/issues/62) +- Devise\_token\_auth without OmniAuth authentication [\#60](https://github.com/lynndylanhurley/devise_token_auth/issues/60) +- Reset Password error [\#59](https://github.com/lynndylanhurley/devise_token_auth/issues/59) +- Confirmable - unconfirmed email [\#58](https://github.com/lynndylanhurley/devise_token_auth/issues/58) +- Email Column Isn't Used for Database Authentication [\#56](https://github.com/lynndylanhurley/devise_token_auth/issues/56) +- Unique Key for Provider and UID Combination [\#55](https://github.com/lynndylanhurley/devise_token_auth/issues/55) +- User Info in separate table or removed [\#53](https://github.com/lynndylanhurley/devise_token_auth/issues/53) +- rename @user to @resource [\#48](https://github.com/lynndylanhurley/devise_token_auth/issues/48) +- Active\_admin issue [\#47](https://github.com/lynndylanhurley/devise_token_auth/issues/47) +- Possible Logout Issue [\#46](https://github.com/lynndylanhurley/devise_token_auth/issues/46) +- Routes not appended to routes.rb [\#45](https://github.com/lynndylanhurley/devise_token_auth/issues/45) +- Return resource.errors.full\_messages in addition to resource.errors [\#44](https://github.com/lynndylanhurley/devise_token_auth/issues/44) +- Devise and Devise\_Token\_Auth in api namespace [\#43](https://github.com/lynndylanhurley/devise_token_auth/issues/43) +- Trackable attributes are not being updated. [\#42](https://github.com/lynndylanhurley/devise_token_auth/issues/42) +- Avoid using respond\_to in application controller [\#41](https://github.com/lynndylanhurley/devise_token_auth/issues/41) +- devise\_token\_auth assumes you want the :confirmable functionality [\#40](https://github.com/lynndylanhurley/devise_token_auth/issues/40) +- undefined method `match' for nil:NilClass [\#39](https://github.com/lynndylanhurley/devise_token_auth/issues/39) +- Expired token aren't removed when session expires [\#38](https://github.com/lynndylanhurley/devise_token_auth/issues/38) +- sign\_up helper [\#37](https://github.com/lynndylanhurley/devise_token_auth/issues/37) +- self.tokens\[client\_id\]\['token'\] != token [\#30](https://github.com/lynndylanhurley/devise_token_auth/issues/30) +- How is the uid generated for non-omniauth users? [\#29](https://github.com/lynndylanhurley/devise_token_auth/issues/29) +- Access to current\_user variable? [\#28](https://github.com/lynndylanhurley/devise_token_auth/issues/28) +- Filter chain halted as :require\_no\_authentication [\#27](https://github.com/lynndylanhurley/devise_token_auth/issues/27) +- Allow additional parameters for registration [\#25](https://github.com/lynndylanhurley/devise_token_auth/issues/25) +- Cannot add more parameters at sign\_up [\#22](https://github.com/lynndylanhurley/devise_token_auth/issues/22) +- Error on Registration [\#21](https://github.com/lynndylanhurley/devise_token_auth/issues/21) +- Error with authentication [\#20](https://github.com/lynndylanhurley/devise_token_auth/issues/20) +- Cascade of Issues with Omniauth\(?\) [\#18](https://github.com/lynndylanhurley/devise_token_auth/issues/18) +- Batch Requests Respond with Original Auth Token [\#17](https://github.com/lynndylanhurley/devise_token_auth/issues/17) +- Sign out with email provider error [\#16](https://github.com/lynndylanhurley/devise_token_auth/issues/16) +- sessions\_controller.rb [\#12](https://github.com/lynndylanhurley/devise_token_auth/issues/12) +- Github login in example is broken [\#10](https://github.com/lynndylanhurley/devise_token_auth/issues/10) +- Facebook auth is broken [\#9](https://github.com/lynndylanhurley/devise_token_auth/issues/9) +- Generator is not working [\#8](https://github.com/lynndylanhurley/devise_token_auth/issues/8) +- Test ticket from Code Climate [\#6](https://github.com/lynndylanhurley/devise_token_auth/issues/6) +- Test ticket from Code Climate [\#5](https://github.com/lynndylanhurley/devise_token_auth/issues/5) +- extending the devise\_token\_auth user model [\#4](https://github.com/lynndylanhurley/devise_token_auth/issues/4) +- A few ideas [\#3](https://github.com/lynndylanhurley/devise_token_auth/issues/3) +- Google Oauth2 does not set cookies in production. [\#1](https://github.com/lynndylanhurley/devise_token_auth/issues/1) + +**Merged pull requests:** + +- Fix for issue \#600 [\#674](https://github.com/lynndylanhurley/devise_token_auth/pull/674) ([milep](https://github.com/milep)) +- Fix setup config example in README [\#665](https://github.com/lynndylanhurley/devise_token_auth/pull/665) ([guich-wo](https://github.com/guich-wo)) +- added bypass\_sign\_in for next version of Devise [\#663](https://github.com/lynndylanhurley/devise_token_auth/pull/663) ([KendallPark](https://github.com/KendallPark)) +- fix method 'is\_json\_api' with active\_model\_serialier v 0.10.0 [\#651](https://github.com/lynndylanhurley/devise_token_auth/pull/651) ([woodcrust](https://github.com/woodcrust)) +- Tokens count overmuch fixed [\#650](https://github.com/lynndylanhurley/devise_token_auth/pull/650) ([JerryGreen](https://github.com/JerryGreen)) +- updates config wrapper to conform with newer idiom [\#648](https://github.com/lynndylanhurley/devise_token_auth/pull/648) ([bvandgrift](https://github.com/bvandgrift)) +- Adding support for devise 4.1.1 [\#642](https://github.com/lynndylanhurley/devise_token_auth/pull/642) ([iainmcg](https://github.com/iainmcg)) +- Updating Devise dependency to max 4.1.1 [\#641](https://github.com/lynndylanhurley/devise_token_auth/pull/641) ([TGRGIT](https://github.com/TGRGIT)) +- Fix yields from controller actions [\#638](https://github.com/lynndylanhurley/devise_token_auth/pull/638) ([tiagojsag](https://github.com/tiagojsag)) +- Fix generator to correctly inject content into the user model in rails 5 [\#636](https://github.com/lynndylanhurley/devise_token_auth/pull/636) ([ethangk](https://github.com/ethangk)) +- fix spelling in comment on token auth concern [\#632](https://github.com/lynndylanhurley/devise_token_auth/pull/632) ([dandlezzz](https://github.com/dandlezzz)) +- fixed devise deprecation warning for config.email\_regexp [\#618](https://github.com/lynndylanhurley/devise_token_auth/pull/618) ([lemuelbarango](https://github.com/lemuelbarango)) +- Revert "Update readme for headers names" [\#592](https://github.com/lynndylanhurley/devise_token_auth/pull/592) ([y4ashida](https://github.com/y4ashida)) +- Update readme for headers names [\#589](https://github.com/lynndylanhurley/devise_token_auth/pull/589) ([y4ashida](https://github.com/y4ashida)) +- Add info to README [\#585](https://github.com/lynndylanhurley/devise_token_auth/pull/585) ([ghost](https://github.com/ghost)) +- Fix typo and remove trailing spaces [\#578](https://github.com/lynndylanhurley/devise_token_auth/pull/578) ([y4ashida](https://github.com/y4ashida)) +- allowing authenticating using headers as well as a post request [\#576](https://github.com/lynndylanhurley/devise_token_auth/pull/576) ([ingolfured](https://github.com/ingolfured)) +- Whitespace: tabs removed [\#574](https://github.com/lynndylanhurley/devise_token_auth/pull/574) ([olleolleolle](https://github.com/olleolleolle)) +- Added dutch translations [\#571](https://github.com/lynndylanhurley/devise_token_auth/pull/571) ([nschmoller](https://github.com/nschmoller)) +- now possible to change headers names in the config file [\#569](https://github.com/lynndylanhurley/devise_token_auth/pull/569) ([ingolfured](https://github.com/ingolfured)) +- User concern: Ensure fallback is in place [\#564](https://github.com/lynndylanhurley/devise_token_auth/pull/564) ([olleolleolle](https://github.com/olleolleolle)) +- Return resource with top-level 'type' member. [\#562](https://github.com/lynndylanhurley/devise_token_auth/pull/562) ([ruimiguelsantos](https://github.com/ruimiguelsantos)) +- Fix devise mapping [\#540](https://github.com/lynndylanhurley/devise_token_auth/pull/540) ([merqlove](https://github.com/merqlove)) +- Make all json responses to be json\_api compliant [\#537](https://github.com/lynndylanhurley/devise_token_auth/pull/537) ([djsegal](https://github.com/djsegal)) +- Avoid sending auth headers if while processing used token is cleared [\#531](https://github.com/lynndylanhurley/devise_token_auth/pull/531) ([virginia-rodriguez](https://github.com/virginia-rodriguez)) +- Add Japanese locale and fix typo [\#530](https://github.com/lynndylanhurley/devise_token_auth/pull/530) ([metalunk](https://github.com/metalunk)) +- Added omniauth post route [\#528](https://github.com/lynndylanhurley/devise_token_auth/pull/528) ([v3rtx](https://github.com/v3rtx)) +- Extract model callbacks [\#525](https://github.com/lynndylanhurley/devise_token_auth/pull/525) ([merqlove](https://github.com/merqlove)) +- create token when no client\_id token [\#523](https://github.com/lynndylanhurley/devise_token_auth/pull/523) ([charlesdg](https://github.com/charlesdg)) +- Fix enable\_standard\_devise\_support in initializer [\#518](https://github.com/lynndylanhurley/devise_token_auth/pull/518) ([halilim](https://github.com/halilim)) +- Make render\_create\_success render valid json\_api [\#513](https://github.com/lynndylanhurley/devise_token_auth/pull/513) ([djsegal](https://github.com/djsegal)) +- Prevent raise of exception if set\_user\_by\_token not defined [\#511](https://github.com/lynndylanhurley/devise_token_auth/pull/511) ([jeryRazakarison](https://github.com/jeryRazakarison)) +- send\_on\_create\_confirmation\_instructions callback isn't defined \(rails 5\) [\#508](https://github.com/lynndylanhurley/devise_token_auth/pull/508) ([fivetwentysix](https://github.com/fivetwentysix)) +- \[REBASE\] Fix rails 5 deprecation and devise parameter sanitization [\#507](https://github.com/lynndylanhurley/devise_token_auth/pull/507) ([fivetwentysix](https://github.com/fivetwentysix)) +- remove deprecations from RegistrationsController [\#506](https://github.com/lynndylanhurley/devise_token_auth/pull/506) ([fivetwentysix](https://github.com/fivetwentysix)) +- Allow new devise version for rails 5 compatibility [\#499](https://github.com/lynndylanhurley/devise_token_auth/pull/499) ([djsegal](https://github.com/djsegal)) +- Spelling mistake [\#493](https://github.com/lynndylanhurley/devise_token_auth/pull/493) ([Tom-Tom](https://github.com/Tom-Tom)) +- Improve Brazilian Portuguese locale [\#491](https://github.com/lynndylanhurley/devise_token_auth/pull/491) ([ssouza](https://github.com/ssouza)) +- fix namespaced mapping name [\#484](https://github.com/lynndylanhurley/devise_token_auth/pull/484) ([paulosoares86](https://github.com/paulosoares86)) +- Locale file for both zh-TW and zh-HK [\#483](https://github.com/lynndylanhurley/devise_token_auth/pull/483) ([TravisTam](https://github.com/TravisTam)) +- Fixed typos and inconsistencies in ru.yml [\#478](https://github.com/lynndylanhurley/devise_token_auth/pull/478) ([fertingoff](https://github.com/fertingoff)) +- Fixes Issue \#362: Fixes for the omniauth redirection issue for namesp… [\#476](https://github.com/lynndylanhurley/devise_token_auth/pull/476) ([devilankur18](https://github.com/devilankur18)) +- removing old tokens when user changes passwords [\#474](https://github.com/lynndylanhurley/devise_token_auth/pull/474) ([paulosoares86](https://github.com/paulosoares86)) +- Move travis to container based configuration [\#470](https://github.com/lynndylanhurley/devise_token_auth/pull/470) ([ValentinTrinque](https://github.com/ValentinTrinque)) +- Prevent helpers being loaded for Rails API’s [\#469](https://github.com/lynndylanhurley/devise_token_auth/pull/469) ([djsegal](https://github.com/djsegal)) +- Reduce dependencies to allow Rails 5.0 [\#467](https://github.com/lynndylanhurley/devise_token_auth/pull/467) ([djsegal](https://github.com/djsegal)) +- Fix locales `errors.messages.already\_in\_use` + clean up [\#466](https://github.com/lynndylanhurley/devise_token_auth/pull/466) ([ValentinTrinque](https://github.com/ValentinTrinque)) +- Added 401 response to failed group authentication [\#446](https://github.com/lynndylanhurley/devise_token_auth/pull/446) ([rstrobl](https://github.com/rstrobl)) +- RU translations [\#441](https://github.com/lynndylanhurley/devise_token_auth/pull/441) ([yivo](https://github.com/yivo)) +- to keep coherent with devise. pt instead of pt-PT.yml [\#436](https://github.com/lynndylanhurley/devise_token_auth/pull/436) ([rmvenancio](https://github.com/rmvenancio)) +- limiting the number of concurrent devices [\#434](https://github.com/lynndylanhurley/devise_token_auth/pull/434) ([paulosoares86](https://github.com/paulosoares86)) +- Raise error in controller method [\#430](https://github.com/lynndylanhurley/devise_token_auth/pull/430) ([ArneZsng](https://github.com/ArneZsng)) +- feat\(enable-standard-devise\): allow configurable support of legacy Devise authentication [\#428](https://github.com/lynndylanhurley/devise_token_auth/pull/428) ([booleanbetrayal](https://github.com/booleanbetrayal)) +- Support for i18n in mailers views [\#427](https://github.com/lynndylanhurley/devise_token_auth/pull/427) ([ponyesteves](https://github.com/ponyesteves)) +- Fix omniauthredirection when under scopes [\#425](https://github.com/lynndylanhurley/devise_token_auth/pull/425) ([xjunior](https://github.com/xjunior)) +- Translation to German [\#423](https://github.com/lynndylanhurley/devise_token_auth/pull/423) ([haslinger](https://github.com/haslinger)) +- fix\(url\): preserve query parameters when building urls [\#421](https://github.com/lynndylanhurley/devise_token_auth/pull/421) ([nbrustein](https://github.com/nbrustein)) +- Change default message for already in use error and added to english … [\#417](https://github.com/lynndylanhurley/devise_token_auth/pull/417) ([ponyesteves](https://github.com/ponyesteves)) +- Issue \#413 [\#414](https://github.com/lynndylanhurley/devise_token_auth/pull/414) ([Carrigan](https://github.com/Carrigan)) +- Add .ruby-version entry to .gitignore [\#412](https://github.com/lynndylanhurley/devise_token_auth/pull/412) ([xymbol](https://github.com/xymbol)) +- 404 for invalid link with password reset token [\#411](https://github.com/lynndylanhurley/devise_token_auth/pull/411) ([rmvenancio](https://github.com/rmvenancio)) +- Portuguese Translation [\#409](https://github.com/lynndylanhurley/devise_token_auth/pull/409) ([rmvenancio](https://github.com/rmvenancio)) +- Added polish translation. [\#405](https://github.com/lynndylanhurley/devise_token_auth/pull/405) ([h3xed](https://github.com/h3xed)) +- Drop .ruby-version file [\#404](https://github.com/lynndylanhurley/devise_token_auth/pull/404) ([xymbol](https://github.com/xymbol)) +- Implement hook methods for customized json rendering [\#384](https://github.com/lynndylanhurley/devise_token_auth/pull/384) ([neutronz](https://github.com/neutronz)) +- Feature/password reset with check fix [\#374](https://github.com/lynndylanhurley/devise_token_auth/pull/374) ([jakubrohleder](https://github.com/jakubrohleder)) +- fix\(oauth\): fixes \#368: do not serialize the entire user object in the url when redirecting from oauth [\#371](https://github.com/lynndylanhurley/devise_token_auth/pull/371) ([nbrustein](https://github.com/nbrustein)) +- Fallback to ActiveModel translations in EmailValidator [\#369](https://github.com/lynndylanhurley/devise_token_auth/pull/369) ([yivo](https://github.com/yivo)) +- Add a Gitter chat badge to README.md [\#360](https://github.com/lynndylanhurley/devise_token_auth/pull/360) ([gitter-badger](https://github.com/gitter-badger)) +- Improvements to the docs. [\#358](https://github.com/lynndylanhurley/devise_token_auth/pull/358) ([aarongray](https://github.com/aarongray)) +- Add description to readme about the devise.rb initializer. [\#356](https://github.com/lynndylanhurley/devise_token_auth/pull/356) ([aarongray](https://github.com/aarongray)) +- Correct handling namespaced resources [\#355](https://github.com/lynndylanhurley/devise_token_auth/pull/355) ([yivo](https://github.com/yivo)) +- Fix concern not being inserted for rails-api apps. [\#350](https://github.com/lynndylanhurley/devise_token_auth/pull/350) ([aarongray](https://github.com/aarongray)) +- Add documentation to explain gotcha with rails-api. [\#349](https://github.com/lynndylanhurley/devise_token_auth/pull/349) ([aarongray](https://github.com/aarongray)) +- Fully support OmniauthCallbacksController action overrides. Fixes \#186. [\#347](https://github.com/lynndylanhurley/devise_token_auth/pull/347) ([tbloncar](https://github.com/tbloncar)) +- \#340 Restrict access to controllers methods [\#341](https://github.com/lynndylanhurley/devise_token_auth/pull/341) ([gkopylov](https://github.com/gkopylov)) +- fix\(omniauth\): fix error in setting text on redirect page [\#336](https://github.com/lynndylanhurley/devise_token_auth/pull/336) ([nbrustein](https://github.com/nbrustein)) +- add Brazilian Portuguese translation \(pt-BR\) [\#331](https://github.com/lynndylanhurley/devise_token_auth/pull/331) ([josiasds](https://github.com/josiasds)) +- Tests to ensure standard devise has greater priority than tokens [\#330](https://github.com/lynndylanhurley/devise_token_auth/pull/330) ([colavitam](https://github.com/colavitam)) +- Fixed error when using standard devise authentication [\#329](https://github.com/lynndylanhurley/devise_token_auth/pull/329) ([colavitam](https://github.com/colavitam)) +- feat\(improved-omniauth\): omniauth sameWindow and inAppBrowser flows [\#323](https://github.com/lynndylanhurley/devise_token_auth/pull/323) ([nbrustein](https://github.com/nbrustein)) +- Fix invalid omniauth redirect [\#322](https://github.com/lynndylanhurley/devise_token_auth/pull/322) ([troggy](https://github.com/troggy)) +- Old password check before password update [\#317](https://github.com/lynndylanhurley/devise_token_auth/pull/317) ([jakubrohleder](https://github.com/jakubrohleder)) +- Remove erroneous colon from before\_action callback [\#310](https://github.com/lynndylanhurley/devise_token_auth/pull/310) ([jmliu](https://github.com/jmliu)) +- Disabled serialization for JSON type columns [\#306](https://github.com/lynndylanhurley/devise_token_auth/pull/306) ([colavitam](https://github.com/colavitam)) +- Set default provider to "email" in migration [\#302](https://github.com/lynndylanhurley/devise_token_auth/pull/302) ([colavitam](https://github.com/colavitam)) +- Fix an issue for not :confirmable users [\#296](https://github.com/lynndylanhurley/devise_token_auth/pull/296) ([sebfie](https://github.com/sebfie)) +- Update README.md [\#295](https://github.com/lynndylanhurley/devise_token_auth/pull/295) ([adisos](https://github.com/adisos)) +- Fix MOUNT\_PATH 'Read More' link [\#294](https://github.com/lynndylanhurley/devise_token_auth/pull/294) ([jmliu](https://github.com/jmliu)) +- Don't send password reset instructions to unconfirmed email [\#288](https://github.com/lynndylanhurley/devise_token_auth/pull/288) ([coryschires](https://github.com/coryschires)) +- Feature/i18n support [\#283](https://github.com/lynndylanhurley/devise_token_auth/pull/283) ([sebfie](https://github.com/sebfie)) +- Update documentation for validate\_token [\#277](https://github.com/lynndylanhurley/devise_token_auth/pull/277) ([adamgall](https://github.com/adamgall)) +- Added json support for tokens [\#276](https://github.com/lynndylanhurley/devise_token_auth/pull/276) ([shicholas](https://github.com/shicholas)) +- perf\(token\_is\_current?\): add simplistic cache to reduce overhead of redundant token checks during validation calls [\#272](https://github.com/lynndylanhurley/devise_token_auth/pull/272) ([booleanbetrayal](https://github.com/booleanbetrayal)) +- perf\(update\_auth\_header\): only lock the resource if we are rotating tokens [\#267](https://github.com/lynndylanhurley/devise_token_auth/pull/267) ([booleanbetrayal](https://github.com/booleanbetrayal)) +- fix\(email-validation\): Update in-use email validation message during registration to allow full\_message use [\#255](https://github.com/lynndylanhurley/devise_token_auth/pull/255) ([booleanbetrayal](https://github.com/booleanbetrayal)) +- fix\(session\#new\): fix unhandled 500 when logging in with valid user and bad password [\#254](https://github.com/lynndylanhurley/devise_token_auth/pull/254) ([mathemagica](https://github.com/mathemagica)) +- feat\(ominauth\): support json-formatted values in omniauth callback. [\#252](https://github.com/lynndylanhurley/devise_token_auth/pull/252) ([nbrustein](https://github.com/nbrustein)) +- fix\(sessions controller\): call reset\_session on destroy [\#251](https://github.com/lynndylanhurley/devise_token_auth/pull/251) ([nbrustein](https://github.com/nbrustein)) +- fix\(resource\_class\): support optional mapping property from set\_user\_by\_token [\#250](https://github.com/lynndylanhurley/devise_token_auth/pull/250) ([booleanbetrayal](https://github.com/booleanbetrayal)) +- Allow current\_password to be supplied when updating profile. [\#240](https://github.com/lynndylanhurley/devise_token_auth/pull/240) ([jasonswett](https://github.com/jasonswett)) +- fixes password reset when not using confirmable [\#225](https://github.com/lynndylanhurley/devise_token_auth/pull/225) ([aesnyder](https://github.com/aesnyder)) +- Fix error when email missing from registration params [\#220](https://github.com/lynndylanhurley/devise_token_auth/pull/220) ([iangreenleaf](https://github.com/iangreenleaf)) +- URI fragment should appear at the end of URL [\#214](https://github.com/lynndylanhurley/devise_token_auth/pull/214) ([edymerchk](https://github.com/edymerchk)) +- Super block yield \(all controllers\) [\#209](https://github.com/lynndylanhurley/devise_token_auth/pull/209) ([sgwilym](https://github.com/sgwilym)) +- Super block yield [\#207](https://github.com/lynndylanhurley/devise_token_auth/pull/207) ([sgwilym](https://github.com/sgwilym)) +- Ability to localize error message [\#206](https://github.com/lynndylanhurley/devise_token_auth/pull/206) ([lda](https://github.com/lda)) +- remove fragment sign \("\#"\) from URLs without fragment [\#205](https://github.com/lynndylanhurley/devise_token_auth/pull/205) ([tomdov](https://github.com/tomdov)) +- Return 422 \(was 500\) when empty body for sign up and account update [\#204](https://github.com/lynndylanhurley/devise_token_auth/pull/204) ([mchavarriagam](https://github.com/mchavarriagam)) +- Users with allowed unconfirmed access can now log in successfully. [\#202](https://github.com/lynndylanhurley/devise_token_auth/pull/202) ([colavitam](https://github.com/colavitam)) +- Authenticating an existing Warden/Devise User [\#200](https://github.com/lynndylanhurley/devise_token_auth/pull/200) ([nickL](https://github.com/nickL)) +- GET sign\_in should direct people to use POST sign\_in rather than raising exception [\#191](https://github.com/lynndylanhurley/devise_token_auth/pull/191) ([milesmatthias](https://github.com/milesmatthias)) +- Ignore 'extra' in Twitter auth response to avoid CookieOverflow. Fixes \#145. [\#179](https://github.com/lynndylanhurley/devise_token_auth/pull/179) ([tbloncar](https://github.com/tbloncar)) +- Some missing as\_json ? [\#152](https://github.com/lynndylanhurley/devise_token_auth/pull/152) ([nicolas-besnard](https://github.com/nicolas-besnard)) +- Check email format on registration [\#150](https://github.com/lynndylanhurley/devise_token_auth/pull/150) ([nicolas-besnard](https://github.com/nicolas-besnard)) +- Actual header key uses dashes, not underscores. [\#143](https://github.com/lynndylanhurley/devise_token_auth/pull/143) ([ragaskar](https://github.com/ragaskar)) +- Username register login [\#128](https://github.com/lynndylanhurley/devise_token_auth/pull/128) ([nicolas-besnard](https://github.com/nicolas-besnard)) +- Check if confirmable is active before skipping confirmation [\#125](https://github.com/lynndylanhurley/devise_token_auth/pull/125) ([nicolas-besnard](https://github.com/nicolas-besnard)) +- Fix links to section about controller integration. [\#117](https://github.com/lynndylanhurley/devise_token_auth/pull/117) ([Le6ow5k1](https://github.com/Le6ow5k1)) +- document GET for /validate\_token [\#113](https://github.com/lynndylanhurley/devise_token_auth/pull/113) ([lukaselmer](https://github.com/lukaselmer)) +- Fix small error in documentation. [\#91](https://github.com/lynndylanhurley/devise_token_auth/pull/91) ([edgarhenriquez](https://github.com/edgarhenriquez)) +- Exclude devise modules [\#85](https://github.com/lynndylanhurley/devise_token_auth/pull/85) ([jartek](https://github.com/jartek)) +- fix\(registration and update\): Ensure UID is updated alongside Email, and case-sensitivity is honored [\#71](https://github.com/lynndylanhurley/devise_token_auth/pull/71) ([booleanbetrayal](https://github.com/booleanbetrayal)) +- Add better guidelines for contributors. [\#67](https://github.com/lynndylanhurley/devise_token_auth/pull/67) ([edgarhenriquez](https://github.com/edgarhenriquez)) +- Use resource\_class to override email confirmation. [\#64](https://github.com/lynndylanhurley/devise_token_auth/pull/64) ([edgarhenriquez](https://github.com/edgarhenriquez)) +- fix\(case-sensitivity\): support devise case\_insensitive\_keys for session ... [\#57](https://github.com/lynndylanhurley/devise_token_auth/pull/57) ([booleanbetrayal](https://github.com/booleanbetrayal)) +- fix\(contention\): fix write contention in update\_auth\_headers and always ... [\#52](https://github.com/lynndylanhurley/devise_token_auth/pull/52) ([booleanbetrayal](https://github.com/booleanbetrayal)) +- Include resource.errors.full\_messages in error response. [\#50](https://github.com/lynndylanhurley/devise_token_auth/pull/50) ([jasonswett](https://github.com/jasonswett)) +- fix\(expiry\): fix an issue where token expiration checks were too permissive [\#49](https://github.com/lynndylanhurley/devise_token_auth/pull/49) ([booleanbetrayal](https://github.com/booleanbetrayal)) +- Update README with Example Generator Command [\#35](https://github.com/lynndylanhurley/devise_token_auth/pull/35) ([wwilkins](https://github.com/wwilkins)) +- Remove OmniAuth dependency [\#26](https://github.com/lynndylanhurley/devise_token_auth/pull/26) ([hannahhoward](https://github.com/hannahhoward)) +- Update README.md [\#24](https://github.com/lynndylanhurley/devise_token_auth/pull/24) ([davidsavoya](https://github.com/davidsavoya)) +- guard against MissingAttributeError during common ActiveRecord operations [\#19](https://github.com/lynndylanhurley/devise_token_auth/pull/19) ([booleanbetrayal](https://github.com/booleanbetrayal)) +- Fix expiry data type [\#11](https://github.com/lynndylanhurley/devise_token_auth/pull/11) ([lonre](https://github.com/lonre)) +- README and travis config tweaks [\#7](https://github.com/lynndylanhurley/devise_token_auth/pull/7) ([guilhermesimoes](https://github.com/guilhermesimoes)) + +# Change Log + +## [0.1.37](https://github.com/lynndylanhurley/devise_token_auth/tree/0.1.37) (2016-01-26) + +[Full Changelog](https://github.com/lynndylanhurley/devise_token_auth/compare/v0.1.37.beta4...0.1.37) + +**Closed issues:** + +- Not working with rails 5 and devise master [\#504](https://github.com/lynndylanhurley/devise_token_auth/issues/504) +- Unpermitted parameters: confirm\_success\_url, config\_name, registration [\#501](https://github.com/lynndylanhurley/devise_token_auth/issues/501) +- Master branch no longer working with devise master branch \(version error\) [\#498](https://github.com/lynndylanhurley/devise_token_auth/issues/498) +- uid is not getting set in git revision 996b9cf23a18 [\#497](https://github.com/lynndylanhurley/devise_token_auth/issues/497) +- ve\_model\_serializer namespace [\#492](https://github.com/lynndylanhurley/devise_token_auth/issues/492) +- User remains logged in when using devise and devise\_token\_auth in the same app [\#486](https://github.com/lynndylanhurley/devise_token_auth/issues/486) +- DEPRECATION WARNING: alias\_method\_chain is deprecated. Rails 5 [\#482](https://github.com/lynndylanhurley/devise_token_auth/issues/482) +- validate\_token - resource\_name - undefined method `name' for nil:NilClass [\#480](https://github.com/lynndylanhurley/devise_token_auth/issues/480) +- Helpers being loaded for Rails API's [\#468](https://github.com/lynndylanhurley/devise_token_auth/issues/468) +- locales `errors.messages.already\_in\_use` seems broken [\#463](https://github.com/lynndylanhurley/devise_token_auth/issues/463) +- omniauth callback redirect not working properly when using namespace/scope [\#362](https://github.com/lynndylanhurley/devise_token_auth/issues/362) +- delete tokens after password change [\#318](https://github.com/lynndylanhurley/devise_token_auth/issues/318) + +**Merged pull requests:** + +- send\_on\_create\_confirmation\_instructions callback isn't defined \(rails 5\) [\#508](https://github.com/lynndylanhurley/devise_token_auth/pull/508) ([fivetwentysix](https://github.com/fivetwentysix)) +- \[REBASE\] Fix rails 5 deprecation and devise parameter sanitization [\#507](https://github.com/lynndylanhurley/devise_token_auth/pull/507) ([fivetwentysix](https://github.com/fivetwentysix)) +- remove deprecations from RegistrationsController [\#506](https://github.com/lynndylanhurley/devise_token_auth/pull/506) ([fivetwentysix](https://github.com/fivetwentysix)) +- Allow new devise version for rails 5 compatibility [\#499](https://github.com/lynndylanhurley/devise_token_auth/pull/499) ([djsegal](https://github.com/djsegal)) +- Spelling mistake [\#493](https://github.com/lynndylanhurley/devise_token_auth/pull/493) ([Tom-Tom](https://github.com/Tom-Tom)) +- Improve Brazilian Portuguese locale [\#491](https://github.com/lynndylanhurley/devise_token_auth/pull/491) ([ssouza](https://github.com/ssouza)) +- fix namespaced mapping name [\#484](https://github.com/lynndylanhurley/devise_token_auth/pull/484) ([paulosoares86](https://github.com/paulosoares86)) +- Locale file for both zh-TW and zh-HK [\#483](https://github.com/lynndylanhurley/devise_token_auth/pull/483) ([TravisTam](https://github.com/TravisTam)) +- Fixed typos and inconsistencies in ru.yml [\#478](https://github.com/lynndylanhurley/devise_token_auth/pull/478) ([fertingoff](https://github.com/fertingoff)) +- Fixes Issue \#362: Fixes for the omniauth redirection issue for namesp… [\#476](https://github.com/lynndylanhurley/devise_token_auth/pull/476) ([devilankur18](https://github.com/devilankur18)) +- removing old tokens when user changes passwords [\#474](https://github.com/lynndylanhurley/devise_token_auth/pull/474) ([paulosoares86](https://github.com/paulosoares86)) +- Move travis to container based configuration [\#470](https://github.com/lynndylanhurley/devise_token_auth/pull/470) ([ValentinTrinque](https://github.com/ValentinTrinque)) +- Prevent helpers being loaded for Rails API’s [\#469](https://github.com/lynndylanhurley/devise_token_auth/pull/469) ([djsegal](https://github.com/djsegal)) +- Reduce dependencies to allow Rails 5.0 [\#467](https://github.com/lynndylanhurley/devise_token_auth/pull/467) ([djsegal](https://github.com/djsegal)) +- Fix locales `errors.messages.already\_in\_use` + clean up [\#466](https://github.com/lynndylanhurley/devise_token_auth/pull/466) ([ValentinTrinque](https://github.com/ValentinTrinque)) +- Fix omniauthredirection when under scopes [\#425](https://github.com/lynndylanhurley/devise_token_auth/pull/425) ([xjunior](https://github.com/xjunior)) + +## [v0.1.37.beta4](https://github.com/lynndylanhurley/devise_token_auth/tree/v0.1.37.beta4) (2015-12-10) +[Full Changelog](https://github.com/lynndylanhurley/devise_token_auth/compare/v0.1.37.beta3...v0.1.37.beta4) + +**Closed issues:** + +- It shows "An error occurred" after omniauth callback [\#445](https://github.com/lynndylanhurley/devise_token_auth/issues/445) +- - [\#444](https://github.com/lynndylanhurley/devise_token_auth/issues/444) +- Put Access Token in body [\#442](https://github.com/lynndylanhurley/devise_token_auth/issues/442) +- Unable to add a new param for sign up [\#440](https://github.com/lynndylanhurley/devise_token_auth/issues/440) +- Undefined method provider from devise\_toke\_auth concerns/user.rb [\#438](https://github.com/lynndylanhurley/devise_token_auth/issues/438) +- Scoped DeviseToken but it still affects the original Omniauth redirects. [\#429](https://github.com/lynndylanhurley/devise_token_auth/issues/429) +- Can't create user via api [\#422](https://github.com/lynndylanhurley/devise_token_auth/issues/422) +- change\_headers\_on\_each\_request and batch requests [\#403](https://github.com/lynndylanhurley/devise_token_auth/issues/403) +- password length [\#380](https://github.com/lynndylanhurley/devise_token_auth/issues/380) +- The action 'twitter' could not be found for DeviseTokenAuth::OmniauthCallbacksController [\#309](https://github.com/lynndylanhurley/devise_token_auth/issues/309) +- undefined method `tokens' for \#\ [\#297](https://github.com/lynndylanhurley/devise_token_auth/issues/297) +- Generating many client tokens [\#210](https://github.com/lynndylanhurley/devise_token_auth/issues/210) + +**Merged pull requests:** + +- RU translations [\#441](https://github.com/lynndylanhurley/devise_token_auth/pull/441) ([yivo](https://github.com/yivo)) +- to keep coherent with devise. pt instead of pt-PT.yml [\#436](https://github.com/lynndylanhurley/devise_token_auth/pull/436) ([rmvenancio](https://github.com/rmvenancio)) +- limiting the number of concurrent devices [\#434](https://github.com/lynndylanhurley/devise_token_auth/pull/434) ([paulosoares86](https://github.com/paulosoares86)) +- Raise error in controller method [\#430](https://github.com/lynndylanhurley/devise_token_auth/pull/430) ([ArneZsng](https://github.com/ArneZsng)) +- feat\(enable-standard-devise\): allow configurable support of legacy Devise authentication [\#428](https://github.com/lynndylanhurley/devise_token_auth/pull/428) ([booleanbetrayal](https://github.com/booleanbetrayal)) +- Support for i18n in mailers views [\#427](https://github.com/lynndylanhurley/devise_token_auth/pull/427) ([ponyesteves](https://github.com/ponyesteves)) +- Translation to German [\#423](https://github.com/lynndylanhurley/devise_token_auth/pull/423) ([haslinger](https://github.com/haslinger)) +- fix\(url\): preserve query parameters when building urls [\#421](https://github.com/lynndylanhurley/devise_token_auth/pull/421) ([nbrustein](https://github.com/nbrustein)) +- Fallback to ActiveModel translations in EmailValidator [\#369](https://github.com/lynndylanhurley/devise_token_auth/pull/369) ([yivo](https://github.com/yivo)) + +## [v0.1.37.beta3](https://github.com/lynndylanhurley/devise_token_auth/tree/v0.1.37.beta3) (2015-10-27) +[Full Changelog](https://github.com/lynndylanhurley/devise_token_auth/compare/v0.1.37.beta2...v0.1.37.beta3) + +**Closed issues:** + +- Password Reset question, do I need my own form? [\#418](https://github.com/lynndylanhurley/devise_token_auth/issues/418) +- seeing other users data after login/out with different users on ionic [\#375](https://github.com/lynndylanhurley/devise_token_auth/issues/375) + +## [v0.1.37.beta2](https://github.com/lynndylanhurley/devise_token_auth/tree/v0.1.37.beta2) (2015-10-25) +[Full Changelog](https://github.com/lynndylanhurley/devise_token_auth/compare/v0.1.37.beta1...v0.1.37.beta2) + +**Closed issues:** + +- The validate\_token function in the readme is missing a parameter [\#413](https://github.com/lynndylanhurley/devise_token_auth/issues/413) + +**Merged pull requests:** + +- Change default message for already in use error and added to english … [\#417](https://github.com/lynndylanhurley/devise_token_auth/pull/417) ([ponyesteves](https://github.com/ponyesteves)) +- Issue \#413 [\#414](https://github.com/lynndylanhurley/devise_token_auth/pull/414) ([Carrigan](https://github.com/Carrigan)) +- 404 for invalid link with password reset token [\#411](https://github.com/lynndylanhurley/devise_token_auth/pull/411) ([rmvenancio](https://github.com/rmvenancio)) + +## [v0.1.37.beta1](https://github.com/lynndylanhurley/devise_token_auth/tree/v0.1.37.beta1) (2015-10-25) +[Full Changelog](https://github.com/lynndylanhurley/devise_token_auth/compare/v0.1.36...v0.1.37.beta1) + +**Closed issues:** + +- Large Size on Disk [\#415](https://github.com/lynndylanhurley/devise_token_auth/issues/415) +- Cannot migrate database: NoMethodError: undefined method `new' for DeviseTokenAuth:Module [\#406](https://github.com/lynndylanhurley/devise_token_auth/issues/406) +- uninitialized constant DeviseTokenAuth::OmniauthCallbacksController::BCrypt [\#393](https://github.com/lynndylanhurley/devise_token_auth/issues/393) +- Devise token auth not found routing error [\#379](https://github.com/lynndylanhurley/devise_token_auth/issues/379) +- undefined method `match' for nil:NilClass [\#201](https://github.com/lynndylanhurley/devise_token_auth/issues/201) + +**Merged pull requests:** + +- Add .ruby-version entry to .gitignore [\#412](https://github.com/lynndylanhurley/devise_token_auth/pull/412) ([xymbol](https://github.com/xymbol)) +- Portuguese Translation [\#409](https://github.com/lynndylanhurley/devise_token_auth/pull/409) ([rmvenancio](https://github.com/rmvenancio)) +- Drop .ruby-version file [\#404](https://github.com/lynndylanhurley/devise_token_auth/pull/404) ([xymbol](https://github.com/xymbol)) +- Feature/password reset with check fix [\#374](https://github.com/lynndylanhurley/devise_token_auth/pull/374) ([jakubrohleder](https://github.com/jakubrohleder)) + +## [v0.1.36](https://github.com/lynndylanhurley/devise_token_auth/tree/v0.1.36) (2015-10-13) +[Full Changelog](https://github.com/lynndylanhurley/devise_token_auth/compare/v0.1.35...v0.1.36) + +## [v0.1.35](https://github.com/lynndylanhurley/devise_token_auth/tree/v0.1.35) (2015-10-13) +[Full Changelog](https://github.com/lynndylanhurley/devise_token_auth/compare/v0.1.34...v0.1.35) + +**Fixed bugs:** + +- Generator doesn't work correctly with mongoid and/or rails-api [\#14](https://github.com/lynndylanhurley/devise_token_auth/issues/14) + +**Closed issues:** + +- Multiple users, returning\(and creating\) wrong model's auth token [\#399](https://github.com/lynndylanhurley/devise_token_auth/issues/399) +- Sign in not success. [\#388](https://github.com/lynndylanhurley/devise_token_auth/issues/388) +- Defining a custom primary key [\#378](https://github.com/lynndylanhurley/devise_token_auth/issues/378) +- omniauth: when redirecting, user object should not be serialized into url [\#368](https://github.com/lynndylanhurley/devise_token_auth/issues/368) +- getting ng-token-auth and devise\_token\_auth to work with OAuth in ionic InAppBrowser [\#367](https://github.com/lynndylanhurley/devise_token_auth/issues/367) +- invalid token in method set\_user\_by\_token on RegistrationsController\#update [\#357](https://github.com/lynndylanhurley/devise_token_auth/issues/357) +- Allow devise patch version updates [\#351](https://github.com/lynndylanhurley/devise_token_auth/issues/351) +- Error validating token [\#348](https://github.com/lynndylanhurley/devise_token_auth/issues/348) +- Allow for HTTP Basic Auth ? [\#337](https://github.com/lynndylanhurley/devise_token_auth/issues/337) +- Allow Omniauth user reset password [\#335](https://github.com/lynndylanhurley/devise_token_auth/issues/335) +- NameError \(uninitialized constant DeviseTokenAuth::Concerns::User::BCrypt\) [\#333](https://github.com/lynndylanhurley/devise_token_auth/issues/333) +- Unpermitted parameters: format, session [\#328](https://github.com/lynndylanhurley/devise_token_auth/issues/328) +- devise token auth + Save Facebook auth\_hash info in database [\#326](https://github.com/lynndylanhurley/devise_token_auth/issues/326) +- Error sending password reset email when not using confirmable \(reopened \#124\) [\#321](https://github.com/lynndylanhurley/devise_token_auth/issues/321) +- Facebook omniauth redirection is missing url when testing on localhost [\#285](https://github.com/lynndylanhurley/devise_token_auth/issues/285) +- Failure route not handled [\#262](https://github.com/lynndylanhurley/devise_token_auth/issues/262) +- Unable to override OmniauthCallbacksController\#redirect\_callbacks [\#186](https://github.com/lynndylanhurley/devise_token_auth/issues/186) + +**Merged pull requests:** + +- Added polish translation. [\#405](https://github.com/lynndylanhurley/devise_token_auth/pull/405) ([h3xed](https://github.com/h3xed)) +- Implement hook methods for customized json rendering [\#384](https://github.com/lynndylanhurley/devise_token_auth/pull/384) ([neutronz](https://github.com/neutronz)) +- fix\(oauth\): fixes \#368: do not serialize the entire user object in the url when redirecting from oauth [\#371](https://github.com/lynndylanhurley/devise_token_auth/pull/371) ([nbrustein](https://github.com/nbrustein)) +- Add a Gitter chat badge to README.md [\#360](https://github.com/lynndylanhurley/devise_token_auth/pull/360) ([gitter-badger](https://github.com/gitter-badger)) +- Improvements to the docs. [\#358](https://github.com/lynndylanhurley/devise_token_auth/pull/358) ([aarongray](https://github.com/aarongray)) +- Add description to readme about the devise.rb initializer. [\#356](https://github.com/lynndylanhurley/devise_token_auth/pull/356) ([aarongray](https://github.com/aarongray)) +- Correct handling namespaced resources [\#355](https://github.com/lynndylanhurley/devise_token_auth/pull/355) ([yivo](https://github.com/yivo)) +- Fix concern not being inserted for rails-api apps. [\#350](https://github.com/lynndylanhurley/devise_token_auth/pull/350) ([aarongray](https://github.com/aarongray)) +- Add documentation to explain gotcha with rails-api. [\#349](https://github.com/lynndylanhurley/devise_token_auth/pull/349) ([aarongray](https://github.com/aarongray)) +- Fully support OmniauthCallbacksController action overrides. Fixes \#186. [\#347](https://github.com/lynndylanhurley/devise_token_auth/pull/347) ([tbloncar](https://github.com/tbloncar)) +- \#340 Restrict access to controllers methods [\#341](https://github.com/lynndylanhurley/devise_token_auth/pull/341) ([gkopylov](https://github.com/gkopylov)) +- fix\(omniauth\): fix error in setting text on redirect page [\#336](https://github.com/lynndylanhurley/devise_token_auth/pull/336) ([nbrustein](https://github.com/nbrustein)) +- Fix invalid omniauth redirect [\#322](https://github.com/lynndylanhurley/devise_token_auth/pull/322) ([troggy](https://github.com/troggy)) + +## [v0.1.34](https://github.com/lynndylanhurley/devise_token_auth/tree/v0.1.34) (2015-08-10) +[Full Changelog](https://github.com/lynndylanhurley/devise_token_auth/compare/v0.1.33...v0.1.34) + +**Implemented enhancements:** + +- Rails generator to update views [\#33](https://github.com/lynndylanhurley/devise_token_auth/issues/33) +- Extract Omniauth attributes assignation into a method [\#31](https://github.com/lynndylanhurley/devise_token_auth/issues/31) + +**Fixed bugs:** + +- Generator issues [\#13](https://github.com/lynndylanhurley/devise_token_auth/issues/13) + +**Closed issues:** + +- Routing error / Preflight request / OPTIONS [\#320](https://github.com/lynndylanhurley/devise_token_auth/issues/320) +- Can't authorize \(user\_signed\_in? always show false\) [\#315](https://github.com/lynndylanhurley/devise_token_auth/issues/315) +- Warden::SessionSerializer - wrong number of arguments \(2 for 1\) [\#312](https://github.com/lynndylanhurley/devise_token_auth/issues/312) +- Having 401 Unauthorized only with mobile [\#305](https://github.com/lynndylanhurley/devise_token_auth/issues/305) +- remove unused nickname, image from user object [\#304](https://github.com/lynndylanhurley/devise_token_auth/issues/304) +- HI, This is more of a doubt since I could not finding anything related to this in your documentation. [\#300](https://github.com/lynndylanhurley/devise_token_auth/issues/300) +- Getting 401's when making requests using iOS/Android clients [\#299](https://github.com/lynndylanhurley/devise_token_auth/issues/299) +- Confirmation URL giving bad arguments [\#293](https://github.com/lynndylanhurley/devise_token_auth/issues/293) +- set\_user\_by\_token not called in overriden controller [\#291](https://github.com/lynndylanhurley/devise_token_auth/issues/291) +- Question: Should we send password reset instructions to unconfirmed emails? [\#287](https://github.com/lynndylanhurley/devise_token_auth/issues/287) +- No route matches \[GET\] "/users/facebook/callback" [\#280](https://github.com/lynndylanhurley/devise_token_auth/issues/280) +- No route matches \[GET\] "/omniauth/:provider" [\#278](https://github.com/lynndylanhurley/devise_token_auth/issues/278) +- How to refresh token/expiry? [\#275](https://github.com/lynndylanhurley/devise_token_auth/issues/275) +- wrong number of arguments \(1 for 0\): in DeviseTokenAuth::RegistrationsController\#create [\#274](https://github.com/lynndylanhurley/devise_token_auth/issues/274) +- Can not save a user with nil tokens attribute [\#271](https://github.com/lynndylanhurley/devise_token_auth/issues/271) +- Shouldn't validate\_token param be access-token, not auth\_token? [\#270](https://github.com/lynndylanhurley/devise_token_auth/issues/270) +- include associations on login [\#269](https://github.com/lynndylanhurley/devise_token_auth/issues/269) +- Getting Unauthorized error even after sending the correct token, uid and client [\#261](https://github.com/lynndylanhurley/devise_token_auth/issues/261) +- Weird error message [\#259](https://github.com/lynndylanhurley/devise_token_auth/issues/259) +- undefined method `provider' for \#\ [\#257](https://github.com/lynndylanhurley/devise_token_auth/issues/257) +- File download with query params [\#246](https://github.com/lynndylanhurley/devise_token_auth/issues/246) +- Info: is devise\_token\_auth compatible with rails 3.2.19? [\#245](https://github.com/lynndylanhurley/devise_token_auth/issues/245) +- Headers required for different methods [\#243](https://github.com/lynndylanhurley/devise_token_auth/issues/243) +- Unpermitted parameters: format, session, lang [\#239](https://github.com/lynndylanhurley/devise_token_auth/issues/239) +- On sign\_in, devise\_token\_auth expects the uid to be the same as the email [\#237](https://github.com/lynndylanhurley/devise_token_auth/issues/237) +- Name conflict with inherited\_resources [\#236](https://github.com/lynndylanhurley/devise_token_auth/issues/236) +- sign\_in will not fetch the token [\#234](https://github.com/lynndylanhurley/devise_token_auth/issues/234) +- Log in request 401 error [\#231](https://github.com/lynndylanhurley/devise_token_auth/issues/231) +- User Registration - "email address already in use" when it is unique [\#230](https://github.com/lynndylanhurley/devise_token_auth/issues/230) +- Devise email validation disabled...why? [\#229](https://github.com/lynndylanhurley/devise_token_auth/issues/229) +- confirm\_success\_url error not working [\#226](https://github.com/lynndylanhurley/devise_token_auth/issues/226) +- pending\_reconfirmation called when confirmable isn't used [\#224](https://github.com/lynndylanhurley/devise_token_auth/issues/224) +- omniauth\_success.html.erb JSON bug [\#221](https://github.com/lynndylanhurley/devise_token_auth/issues/221) +- Using devise\_token\_auth and ng\_token\_auth with angularJS in an Ionic Hybrid application [\#218](https://github.com/lynndylanhurley/devise_token_auth/issues/218) +- Where can I got token? [\#217](https://github.com/lynndylanhurley/devise_token_auth/issues/217) +- URI fragment prevent to send params in Confirmation URL [\#213](https://github.com/lynndylanhurley/devise_token_auth/issues/213) +- Limit tokens hash? [\#208](https://github.com/lynndylanhurley/devise_token_auth/issues/208) +- 500 error returned when no data is POSTed to registration controller [\#203](https://github.com/lynndylanhurley/devise_token_auth/issues/203) +- DELETE method becoming OPTIONS @ Heroku [\#197](https://github.com/lynndylanhurley/devise_token_auth/issues/197) +- 40 Mb log file and 1 minute to have token with curl [\#195](https://github.com/lynndylanhurley/devise_token_auth/issues/195) +- 401 unauthorized [\#193](https://github.com/lynndylanhurley/devise_token_auth/issues/193) +- GET requests to sign\_in shouldn't raise an exception [\#190](https://github.com/lynndylanhurley/devise_token_auth/issues/190) +- Api not locked by default [\#189](https://github.com/lynndylanhurley/devise_token_auth/issues/189) +- Rails 4.1 [\#187](https://github.com/lynndylanhurley/devise_token_auth/issues/187) +- Token based authentication with no sessions [\#183](https://github.com/lynndylanhurley/devise_token_auth/issues/183) +- undefined method `authenticate\_user!' [\#182](https://github.com/lynndylanhurley/devise_token_auth/issues/182) +- confirm\_success\_url shouldn't be a required param [\#176](https://github.com/lynndylanhurley/devise_token_auth/issues/176) +- Provide an OAuth implementation for native apps [\#175](https://github.com/lynndylanhurley/devise_token_auth/issues/175) +- getting an argument error when trying to use omniauth [\#174](https://github.com/lynndylanhurley/devise_token_auth/issues/174) +- Sign in via username doesn't seem to work correctly. [\#173](https://github.com/lynndylanhurley/devise_token_auth/issues/173) +- Cannot use + sign in email address. [\#171](https://github.com/lynndylanhurley/devise_token_auth/issues/171) +- How can i authenticate using curl and get private entries ! [\#167](https://github.com/lynndylanhurley/devise_token_auth/issues/167) +- Pessimistic Locking produces ArgumentError [\#165](https://github.com/lynndylanhurley/devise_token_auth/issues/165) +- POTENTIAL SECURITY RISK: Setting confirm\_success\_url and redirect\_url via API [\#162](https://github.com/lynndylanhurley/devise_token_auth/issues/162) +- Sign out just on client side ? [\#161](https://github.com/lynndylanhurley/devise_token_auth/issues/161) +- Unpermitted parameter: redirect\_url [\#160](https://github.com/lynndylanhurley/devise_token_auth/issues/160) +- Issues using devise and devise\_token\_auth [\#159](https://github.com/lynndylanhurley/devise_token_auth/issues/159) +- Add role based authorization [\#158](https://github.com/lynndylanhurley/devise_token_auth/issues/158) +- Not compatible with ActiveAdmin [\#156](https://github.com/lynndylanhurley/devise_token_auth/issues/156) +- \[Duplicate\] is devise\_invitable supported? [\#154](https://github.com/lynndylanhurley/devise_token_auth/issues/154) +- User can register with a "false" email [\#149](https://github.com/lynndylanhurley/devise_token_auth/issues/149) +- /validate\_token [\#148](https://github.com/lynndylanhurley/devise_token_auth/issues/148) +- Email confirmation link [\#147](https://github.com/lynndylanhurley/devise_token_auth/issues/147) +- Tokens field on database [\#146](https://github.com/lynndylanhurley/devise_token_auth/issues/146) +- Twitter OAuth always throughs CookieOverflow [\#145](https://github.com/lynndylanhurley/devise_token_auth/issues/145) +- Is there a way to configure apiUrl for both dev and prod? [\#144](https://github.com/lynndylanhurley/devise_token_auth/issues/144) +- Getting 401 unauthorized on login attempt [\#142](https://github.com/lynndylanhurley/devise_token_auth/issues/142) +- Comparing with jwt [\#140](https://github.com/lynndylanhurley/devise_token_auth/issues/140) +- Can't get omniauth to work \(error in redirect\_callbacks\) [\#139](https://github.com/lynndylanhurley/devise_token_auth/issues/139) +- Change controller inheritance [\#138](https://github.com/lynndylanhurley/devise_token_auth/issues/138) +- Reset Password call returns 400 for Not Found user [\#137](https://github.com/lynndylanhurley/devise_token_auth/issues/137) +- The gem is too big. Please take care of it. [\#136](https://github.com/lynndylanhurley/devise_token_auth/issues/136) +- Error when loging with facebook the second time without logout [\#135](https://github.com/lynndylanhurley/devise_token_auth/issues/135) +- OmniAuth redirect doesn't work if using the generated mount\_devise\_token route [\#133](https://github.com/lynndylanhurley/devise_token_auth/issues/133) +- Missing template /omniauth\_response [\#132](https://github.com/lynndylanhurley/devise_token_auth/issues/132) +- Unpermitted parameter: session [\#130](https://github.com/lynndylanhurley/devise_token_auth/issues/130) +- OAuth error: We're sorry, but something went wrong [\#129](https://github.com/lynndylanhurley/devise_token_auth/issues/129) +- Would it be useful to integrate login with username ? [\#127](https://github.com/lynndylanhurley/devise_token_auth/issues/127) +- Sign in with login instead of email [\#126](https://github.com/lynndylanhurley/devise_token_auth/issues/126) +- Error sending password reset email when not using confirmable [\#124](https://github.com/lynndylanhurley/devise_token_auth/issues/124) +- Using expired token for parallel calls [\#123](https://github.com/lynndylanhurley/devise_token_auth/issues/123) +- User tokens don't properly deserialize [\#121](https://github.com/lynndylanhurley/devise_token_auth/issues/121) +- Could not load 'omniauth' [\#118](https://github.com/lynndylanhurley/devise_token_auth/issues/118) +- bad argument \(expected URI object or URI string\) [\#116](https://github.com/lynndylanhurley/devise_token_auth/issues/116) +- devise\_token\_auth for public API, but devise for rest of app? [\#114](https://github.com/lynndylanhurley/devise_token_auth/issues/114) +- Omniauthable deleted on UsersConcern : Why ? [\#111](https://github.com/lynndylanhurley/devise_token_auth/issues/111) +- Unrequired route [\#110](https://github.com/lynndylanhurley/devise_token_auth/issues/110) +- raises NoMethodError instead of displaying error when email is missing [\#108](https://github.com/lynndylanhurley/devise_token_auth/issues/108) +- Error with RailsAdmin. "The action 'new' could not be found for DeviseTokenAuth::SessionsController" [\#107](https://github.com/lynndylanhurley/devise_token_auth/issues/107) +- Circular dependency detected while autoloading constant Api [\#106](https://github.com/lynndylanhurley/devise_token_auth/issues/106) +- Can't Authenticate via cURL [\#105](https://github.com/lynndylanhurley/devise_token_auth/issues/105) +- Unpermitted parameters: user, registration [\#104](https://github.com/lynndylanhurley/devise_token_auth/issues/104) +- BCrypt::Errors::InvalidSalt errors [\#103](https://github.com/lynndylanhurley/devise_token_auth/issues/103) +- Active job token expiring integration [\#102](https://github.com/lynndylanhurley/devise_token_auth/issues/102) +- The action 'new' could not be found for DeviseTokenAuth::RegistrationsController [\#100](https://github.com/lynndylanhurley/devise_token_auth/issues/100) +- Disable confirmable [\#99](https://github.com/lynndylanhurley/devise_token_auth/issues/99) +- responders - rails 4.2 [\#98](https://github.com/lynndylanhurley/devise_token_auth/issues/98) +- forward skip to devise [\#97](https://github.com/lynndylanhurley/devise_token_auth/issues/97) +- API versioning the devise scope of token validation and ominiauth controller path will wrap up [\#96](https://github.com/lynndylanhurley/devise_token_auth/issues/96) +- Overwriting default "from" email address [\#94](https://github.com/lynndylanhurley/devise_token_auth/issues/94) +- uninitialized constant DeviseTokenAuth [\#92](https://github.com/lynndylanhurley/devise_token_auth/issues/92) +- change\_headers\_on\_each\_request not working expiry header empty [\#90](https://github.com/lynndylanhurley/devise_token_auth/issues/90) +- Gem render consistency [\#87](https://github.com/lynndylanhurley/devise_token_auth/issues/87) +- Sample Sessions Controller for logging in via Rails View. [\#86](https://github.com/lynndylanhurley/devise_token_auth/issues/86) +- Change authorization key: Use phone\_number instead of email [\#84](https://github.com/lynndylanhurley/devise_token_auth/issues/84) +- Conflict with active\_admin gem [\#83](https://github.com/lynndylanhurley/devise_token_auth/issues/83) +- NoMethodError in DeviseTokenAuth::OmniauthCallbacksController\#redirect\_callbacks [\#82](https://github.com/lynndylanhurley/devise_token_auth/issues/82) +- All the APIs are getting 'Authorized users only' [\#81](https://github.com/lynndylanhurley/devise_token_auth/issues/81) +- Is Devise option Rememberable required ? [\#80](https://github.com/lynndylanhurley/devise_token_auth/issues/80) +- Problem with skip\_confirmation! [\#78](https://github.com/lynndylanhurley/devise_token_auth/issues/78) +- Cannot reset password if registered by omniauth [\#77](https://github.com/lynndylanhurley/devise_token_auth/issues/77) +- NoMethodError at /omniauth/facebook/callback - undefined method `\[\]' for nil:NilClass [\#76](https://github.com/lynndylanhurley/devise_token_auth/issues/76) +- Skipping Registrations Controller Altogether [\#70](https://github.com/lynndylanhurley/devise_token_auth/issues/70) +- Problem in validate\_token if the model is in a namespace [\#69](https://github.com/lynndylanhurley/devise_token_auth/issues/69) +- Cannot send confirmation email if there is no 'User' model [\#68](https://github.com/lynndylanhurley/devise_token_auth/issues/68) +- Better guidelines for contributors [\#65](https://github.com/lynndylanhurley/devise_token_auth/issues/65) +- admin namespace [\#63](https://github.com/lynndylanhurley/devise_token_auth/issues/63) +- Devise trackable module not working [\#62](https://github.com/lynndylanhurley/devise_token_auth/issues/62) +- Devise\_token\_auth without OmniAuth authentication [\#60](https://github.com/lynndylanhurley/devise_token_auth/issues/60) +- Reset Password error [\#59](https://github.com/lynndylanhurley/devise_token_auth/issues/59) +- Confirmable - unconfirmed email [\#58](https://github.com/lynndylanhurley/devise_token_auth/issues/58) +- Email Column Isn't Used for Database Authentication [\#56](https://github.com/lynndylanhurley/devise_token_auth/issues/56) +- Unique Key for Provider and UID Combination [\#55](https://github.com/lynndylanhurley/devise_token_auth/issues/55) +- User Info in separate table or removed [\#53](https://github.com/lynndylanhurley/devise_token_auth/issues/53) +- rename @user to @resource [\#48](https://github.com/lynndylanhurley/devise_token_auth/issues/48) +- Active\_admin issue [\#47](https://github.com/lynndylanhurley/devise_token_auth/issues/47) +- Possible Logout Issue [\#46](https://github.com/lynndylanhurley/devise_token_auth/issues/46) +- Routes not appended to routes.rb [\#45](https://github.com/lynndylanhurley/devise_token_auth/issues/45) +- Return resource.errors.full\_messages in addition to resource.errors [\#44](https://github.com/lynndylanhurley/devise_token_auth/issues/44) +- Devise and Devise\_Token\_Auth in api namespace [\#43](https://github.com/lynndylanhurley/devise_token_auth/issues/43) +- Trackable attributes are not being updated. [\#42](https://github.com/lynndylanhurley/devise_token_auth/issues/42) +- Avoid using respond\_to in application controller [\#41](https://github.com/lynndylanhurley/devise_token_auth/issues/41) +- devise\_token\_auth assumes you want the :confirmable functionality [\#40](https://github.com/lynndylanhurley/devise_token_auth/issues/40) +- undefined method `match' for nil:NilClass [\#39](https://github.com/lynndylanhurley/devise_token_auth/issues/39) +- Expired token aren't removed when session expires [\#38](https://github.com/lynndylanhurley/devise_token_auth/issues/38) +- sign\_up helper [\#37](https://github.com/lynndylanhurley/devise_token_auth/issues/37) +- self.tokens\[client\_id\]\['token'\] != token [\#30](https://github.com/lynndylanhurley/devise_token_auth/issues/30) +- How is the uid generated for non-omniauth users? [\#29](https://github.com/lynndylanhurley/devise_token_auth/issues/29) +- Access to current\_user variable? [\#28](https://github.com/lynndylanhurley/devise_token_auth/issues/28) +- Filter chain halted as :require\_no\_authentication [\#27](https://github.com/lynndylanhurley/devise_token_auth/issues/27) +- Allow additional parameters for registration [\#25](https://github.com/lynndylanhurley/devise_token_auth/issues/25) +- Cannot add more parameters at sign\_up [\#22](https://github.com/lynndylanhurley/devise_token_auth/issues/22) +- Error on Registration [\#21](https://github.com/lynndylanhurley/devise_token_auth/issues/21) +- Error with authentication [\#20](https://github.com/lynndylanhurley/devise_token_auth/issues/20) +- Cascade of Issues with Omniauth\(?\) [\#18](https://github.com/lynndylanhurley/devise_token_auth/issues/18) +- Batch Requests Respond with Original Auth Token [\#17](https://github.com/lynndylanhurley/devise_token_auth/issues/17) +- Sign out with email provider error [\#16](https://github.com/lynndylanhurley/devise_token_auth/issues/16) +- sessions\_controller.rb [\#12](https://github.com/lynndylanhurley/devise_token_auth/issues/12) +- Github login in example is broken [\#10](https://github.com/lynndylanhurley/devise_token_auth/issues/10) +- Facebook auth is broken [\#9](https://github.com/lynndylanhurley/devise_token_auth/issues/9) +- Generator is not working [\#8](https://github.com/lynndylanhurley/devise_token_auth/issues/8) +- Test ticket from Code Climate [\#6](https://github.com/lynndylanhurley/devise_token_auth/issues/6) +- Test ticket from Code Climate [\#5](https://github.com/lynndylanhurley/devise_token_auth/issues/5) +- extending the devise\_token\_auth user model [\#4](https://github.com/lynndylanhurley/devise_token_auth/issues/4) +- A few ideas [\#3](https://github.com/lynndylanhurley/devise_token_auth/issues/3) +- Google Oauth2 does not set cookies in production. [\#1](https://github.com/lynndylanhurley/devise_token_auth/issues/1) + +**Merged pull requests:** + +- add Brazilian Portuguese translation \(pt-BR\) [\#331](https://github.com/lynndylanhurley/devise_token_auth/pull/331) ([josiasds](https://github.com/josiasds)) +- Tests to ensure standard devise has greater priority than tokens [\#330](https://github.com/lynndylanhurley/devise_token_auth/pull/330) ([colavitam](https://github.com/colavitam)) +- Fixed error when using standard devise authentication [\#329](https://github.com/lynndylanhurley/devise_token_auth/pull/329) ([colavitam](https://github.com/colavitam)) +- feat\(improved-omniauth\): omniauth sameWindow and inAppBrowser flows [\#323](https://github.com/lynndylanhurley/devise_token_auth/pull/323) ([nbrustein](https://github.com/nbrustein)) +- Old password check before password update [\#317](https://github.com/lynndylanhurley/devise_token_auth/pull/317) ([jakubrohleder](https://github.com/jakubrohleder)) +- Remove erroneous colon from before\_action callback [\#310](https://github.com/lynndylanhurley/devise_token_auth/pull/310) ([jmliu](https://github.com/jmliu)) +- Disabled serialization for JSON type columns [\#306](https://github.com/lynndylanhurley/devise_token_auth/pull/306) ([colavitam](https://github.com/colavitam)) +- Set default provider to "email" in migration [\#302](https://github.com/lynndylanhurley/devise_token_auth/pull/302) ([colavitam](https://github.com/colavitam)) +- Fix an issue for not :confirmable users [\#296](https://github.com/lynndylanhurley/devise_token_auth/pull/296) ([sebfie](https://github.com/sebfie)) +- Update README.md [\#295](https://github.com/lynndylanhurley/devise_token_auth/pull/295) ([adisos](https://github.com/adisos)) +- Fix MOUNT\_PATH 'Read More' link [\#294](https://github.com/lynndylanhurley/devise_token_auth/pull/294) ([jmliu](https://github.com/jmliu)) +- Don't send password reset instructions to unconfirmed email [\#288](https://github.com/lynndylanhurley/devise_token_auth/pull/288) ([coryschires](https://github.com/coryschires)) +- Feature/i18n support [\#283](https://github.com/lynndylanhurley/devise_token_auth/pull/283) ([sebfie](https://github.com/sebfie)) +- Update documentation for validate\_token [\#277](https://github.com/lynndylanhurley/devise_token_auth/pull/277) ([adamgall](https://github.com/adamgall)) +- Added json support for tokens [\#276](https://github.com/lynndylanhurley/devise_token_auth/pull/276) ([shicholas](https://github.com/shicholas)) +- perf\(token\_is\_current?\): add simplistic cache to reduce overhead of redundant token checks during validation calls [\#272](https://github.com/lynndylanhurley/devise_token_auth/pull/272) ([booleanbetrayal](https://github.com/booleanbetrayal)) +- perf\(update\_auth\_header\): only lock the resource if we are rotating tokens [\#267](https://github.com/lynndylanhurley/devise_token_auth/pull/267) ([booleanbetrayal](https://github.com/booleanbetrayal)) +- fix\(email-validation\): Update in-use email validation message during registration to allow full\_message use [\#255](https://github.com/lynndylanhurley/devise_token_auth/pull/255) ([booleanbetrayal](https://github.com/booleanbetrayal)) +- fix\(session\#new\): fix unhandled 500 when logging in with valid user and bad password [\#254](https://github.com/lynndylanhurley/devise_token_auth/pull/254) ([mathemagica](https://github.com/mathemagica)) +- feat\(ominauth\): support json-formatted values in omniauth callback. [\#252](https://github.com/lynndylanhurley/devise_token_auth/pull/252) ([nbrustein](https://github.com/nbrustein)) +- fix\(sessions controller\): call reset\_session on destroy [\#251](https://github.com/lynndylanhurley/devise_token_auth/pull/251) ([nbrustein](https://github.com/nbrustein)) +- fix\(resource\_class\): support optional mapping property from set\_user\_by\_token [\#250](https://github.com/lynndylanhurley/devise_token_auth/pull/250) ([booleanbetrayal](https://github.com/booleanbetrayal)) +- Allow current\_password to be supplied when updating profile. [\#240](https://github.com/lynndylanhurley/devise_token_auth/pull/240) ([jasonswett](https://github.com/jasonswett)) +- fixes password reset when not using confirmable [\#225](https://github.com/lynndylanhurley/devise_token_auth/pull/225) ([aesnyder](https://github.com/aesnyder)) +- Fix error when email missing from registration params [\#220](https://github.com/lynndylanhurley/devise_token_auth/pull/220) ([iangreenleaf](https://github.com/iangreenleaf)) +- URI fragment should appear at the end of URL [\#214](https://github.com/lynndylanhurley/devise_token_auth/pull/214) ([edymerchk](https://github.com/edymerchk)) +- Super block yield \(all controllers\) [\#209](https://github.com/lynndylanhurley/devise_token_auth/pull/209) ([sgwilym](https://github.com/sgwilym)) +- Super block yield [\#207](https://github.com/lynndylanhurley/devise_token_auth/pull/207) ([sgwilym](https://github.com/sgwilym)) +- Ability to localize error message [\#206](https://github.com/lynndylanhurley/devise_token_auth/pull/206) ([lda](https://github.com/lda)) +- remove fragment sign \("\#"\) from URLs without fragment [\#205](https://github.com/lynndylanhurley/devise_token_auth/pull/205) ([tomdov](https://github.com/tomdov)) +- Return 422 \(was 500\) when empty body for sign up and account update [\#204](https://github.com/lynndylanhurley/devise_token_auth/pull/204) ([mchavarriagam](https://github.com/mchavarriagam)) +- Users with allowed unconfirmed access can now log in successfully. [\#202](https://github.com/lynndylanhurley/devise_token_auth/pull/202) ([colavitam](https://github.com/colavitam)) +- Authenticating an existing Warden/Devise User [\#200](https://github.com/lynndylanhurley/devise_token_auth/pull/200) ([nickL](https://github.com/nickL)) +- GET sign\_in should direct people to use POST sign\_in rather than raising exception [\#191](https://github.com/lynndylanhurley/devise_token_auth/pull/191) ([milesmatthias](https://github.com/milesmatthias)) +- Ignore 'extra' in Twitter auth response to avoid CookieOverflow. Fixes \#145. [\#179](https://github.com/lynndylanhurley/devise_token_auth/pull/179) ([tbloncar](https://github.com/tbloncar)) +- Some missing as\_json ? [\#152](https://github.com/lynndylanhurley/devise_token_auth/pull/152) ([nicolas-besnard](https://github.com/nicolas-besnard)) +- Check email format on registration [\#150](https://github.com/lynndylanhurley/devise_token_auth/pull/150) ([nicolas-besnard](https://github.com/nicolas-besnard)) +- Actual header key uses dashes, not underscores. [\#143](https://github.com/lynndylanhurley/devise_token_auth/pull/143) ([ragaskar](https://github.com/ragaskar)) +- Username register login [\#128](https://github.com/lynndylanhurley/devise_token_auth/pull/128) ([nicolas-besnard](https://github.com/nicolas-besnard)) +- Check if confirmable is active before skipping confirmation [\#125](https://github.com/lynndylanhurley/devise_token_auth/pull/125) ([nicolas-besnard](https://github.com/nicolas-besnard)) +- Fix links to section about controller integration. [\#117](https://github.com/lynndylanhurley/devise_token_auth/pull/117) ([Le6ow5k1](https://github.com/Le6ow5k1)) +- document GET for /validate\_token [\#113](https://github.com/lynndylanhurley/devise_token_auth/pull/113) ([lukaselmer](https://github.com/lukaselmer)) +- Fix small error in documentation. [\#91](https://github.com/lynndylanhurley/devise_token_auth/pull/91) ([edgarhenriquez](https://github.com/edgarhenriquez)) +- Exclude devise modules [\#85](https://github.com/lynndylanhurley/devise_token_auth/pull/85) ([jartek](https://github.com/jartek)) +- fix\(registration and update\): Ensure UID is updated alongside Email, and case-sensitivity is honored [\#71](https://github.com/lynndylanhurley/devise_token_auth/pull/71) ([booleanbetrayal](https://github.com/booleanbetrayal)) +- Add better guidelines for contributors. [\#67](https://github.com/lynndylanhurley/devise_token_auth/pull/67) ([edgarhenriquez](https://github.com/edgarhenriquez)) +- Use resource\_class to override email confirmation. [\#64](https://github.com/lynndylanhurley/devise_token_auth/pull/64) ([edgarhenriquez](https://github.com/edgarhenriquez)) +- fix\(case-sensitivity\): support devise case\_insensitive\_keys for session ... [\#57](https://github.com/lynndylanhurley/devise_token_auth/pull/57) ([booleanbetrayal](https://github.com/booleanbetrayal)) +- fix\(contention\): fix write contention in update\_auth\_headers and always ... [\#52](https://github.com/lynndylanhurley/devise_token_auth/pull/52) ([booleanbetrayal](https://github.com/booleanbetrayal)) +- Include resource.errors.full\_messages in error response. [\#50](https://github.com/lynndylanhurley/devise_token_auth/pull/50) ([jasonswett](https://github.com/jasonswett)) +- fix\(expiry\): fix an issue where token expiration checks were too permissive [\#49](https://github.com/lynndylanhurley/devise_token_auth/pull/49) ([booleanbetrayal](https://github.com/booleanbetrayal)) +- Update README with Example Generator Command [\#35](https://github.com/lynndylanhurley/devise_token_auth/pull/35) ([wwilkins](https://github.com/wwilkins)) +- Remove OmniAuth dependency [\#26](https://github.com/lynndylanhurley/devise_token_auth/pull/26) ([hannahhoward](https://github.com/hannahhoward)) +- Update README.md [\#24](https://github.com/lynndylanhurley/devise_token_auth/pull/24) ([davidsavoya](https://github.com/davidsavoya)) +- guard against MissingAttributeError during common ActiveRecord operations [\#19](https://github.com/lynndylanhurley/devise_token_auth/pull/19) ([booleanbetrayal](https://github.com/booleanbetrayal)) +- Fix expiry data type [\#11](https://github.com/lynndylanhurley/devise_token_auth/pull/11) ([lonre](https://github.com/lonre)) +- README and travis config tweaks [\#7](https://github.com/lynndylanhurley/devise_token_auth/pull/7) ([guilhermesimoes](https://github.com/guilhermesimoes)) + + + +\* *This Change Log was automatically generated by [github_changelog_generator](https://github.com/skywinder/Github-Changelog-Generator)* + +\* *This Change Log was automatically generated by [github_changelog_generator](https://github.com/skywinder/Github-Changelog-Generator)* + +\* *This Change Log was automatically generated by [github_changelog_generator](https://github.com/skywinder/Github-Changelog-Generator)* + +\* *This Change Log was automatically generated by [github_changelog_generator](https://github.com/skywinder/Github-Changelog-Generator)* + +\* *This Change Log was automatically generated by [github_changelog_generator](https://github.com/skywinder/Github-Changelog-Generator)* \ No newline at end of file diff --git a/Gemfile b/Gemfile index 0822904c2..21a0c30e6 100644 --- a/Gemfile +++ b/Gemfile @@ -15,10 +15,10 @@ gemspec group :development, :test do gem 'thor' - gem "figaro", :github => 'laserlemon/figaro' - gem 'omniauth-github', :git => 'git://github.com/intridea/omniauth-github.git' - gem 'omniauth-facebook', :git => 'git://github.com/mkdynamic/omniauth-facebook.git' - gem 'omniauth-google-oauth2', :git => 'git://github.com/zquestz/omniauth-google-oauth2.git' + gem "figaro", :git => 'https://github.com/laserlemon/figaro' + gem 'omniauth-github', :git => 'https://github.com/intridea/omniauth-github' + gem 'omniauth-facebook', :git => 'https://github.com/mkdynamic/omniauth-facebook' + gem 'omniauth-google-oauth2', :git => 'https://github.com/zquestz/omniauth-google-oauth2' gem 'rack-cors', :require => 'rack/cors' gem 'attr_encrypted' @@ -34,9 +34,14 @@ group :development, :test do gem 'guard-minitest' gem 'faker' gem 'fuzz_ball' + gem 'mocha' end # code coverage, metrics group :test do gem "codeclimate-test-reporter", require: nil end + +group :development do + gem "github_changelog_generator" +end \ No newline at end of file diff --git a/Gemfile.lock b/Gemfile.lock index cdf4181c9..d66b604a8 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,207 +1,261 @@ GIT - remote: git://github.com/intridea/omniauth-github.git - revision: 21fa5e1a7295a11eae42846690b1eee88e57c23a + remote: https://github.com/intridea/omniauth-github + revision: a893c2bc45d3c869ada960fddca97d6cba28082d specs: - omniauth-github (1.1.2) - omniauth (~> 1.0) - omniauth-oauth2 (~> 1.1) + omniauth-github (1.2.3) + omniauth (~> 1.5) + omniauth-oauth2 (>= 1.4.0, < 2.0) GIT - remote: git://github.com/laserlemon/figaro.git - revision: 9f54872dfc1a972b4a971211706272f0f38495f4 + remote: https://github.com/laserlemon/figaro + revision: 8dd678f5075272138acf4b56682b8b1cbcd6ce10 specs: - figaro (1.0.0.rc1) + figaro (1.1.1) thor (~> 0.14) GIT - remote: git://github.com/mkdynamic/omniauth-facebook.git - revision: ee4fb4dd6f664b3223974c229fda36169309e9ec + remote: https://github.com/mkdynamic/omniauth-facebook + revision: 19634473820d0190a5112f6b42266ef98c8ee276 specs: - omniauth-facebook (2.0.0) + omniauth-facebook (4.0.0) omniauth-oauth2 (~> 1.2) GIT - remote: git://github.com/zquestz/omniauth-google-oauth2.git - revision: a40a748be080cd3a83808ef98afcbf590d7ffbba + remote: https://github.com/zquestz/omniauth-google-oauth2 + revision: 9a9ef392fdf93d2e711823b88bf821a3f54b97a4 specs: - omniauth-google-oauth2 (0.2.5) - omniauth (> 1.0) - omniauth-oauth2 (~> 1.1) + omniauth-google-oauth2 (0.5.0) + jwt (~> 1.5.2) + multi_json (~> 1.3) + omniauth (>= 1.1.1) + omniauth-oauth2 (>= 1.3.1) PATH remote: . specs: - devise_token_auth (0.1.30.beta5) - devise (~> 3.3) - rails (~> 4.1) + devise_token_auth (0.1.42) + devise (> 3.5.2, < 4.4) + rails (< 6) GEM remote: https://rubygems.org/ specs: - actionmailer (4.1.6) - actionpack (= 4.1.6) - actionview (= 4.1.6) + actionmailer (4.2.8) + actionpack (= 4.2.8) + actionview (= 4.2.8) + activejob (= 4.2.8) mail (~> 2.5, >= 2.5.4) - actionpack (4.1.6) - actionview (= 4.1.6) - activesupport (= 4.1.6) - rack (~> 1.5.2) + rails-dom-testing (~> 1.0, >= 1.0.5) + actionpack (4.2.8) + actionview (= 4.2.8) + activesupport (= 4.2.8) + rack (~> 1.6) rack-test (~> 0.6.2) - actionview (4.1.6) - activesupport (= 4.1.6) + rails-dom-testing (~> 1.0, >= 1.0.5) + rails-html-sanitizer (~> 1.0, >= 1.0.2) + actionview (4.2.8) + activesupport (= 4.2.8) builder (~> 3.1) erubis (~> 2.7.0) - activemodel (4.1.6) - activesupport (= 4.1.6) + rails-dom-testing (~> 1.0, >= 1.0.5) + rails-html-sanitizer (~> 1.0, >= 1.0.3) + activejob (4.2.8) + activesupport (= 4.2.8) + globalid (>= 0.3.0) + activemodel (4.2.8) + activesupport (= 4.2.8) builder (~> 3.1) - activerecord (4.1.6) - activemodel (= 4.1.6) - activesupport (= 4.1.6) - arel (~> 5.0.0) - activesupport (4.1.6) - i18n (~> 0.6, >= 0.6.9) - json (~> 1.7, >= 1.7.7) + activerecord (4.2.8) + activemodel (= 4.2.8) + activesupport (= 4.2.8) + arel (~> 6.0) + activesupport (4.2.8) + i18n (~> 0.7) minitest (~> 5.1) - thread_safe (~> 0.1) + thread_safe (~> 0.3, >= 0.3.4) tzinfo (~> 1.1) - ansi (1.4.3) - arel (5.0.1.20140414130214) - attr_encrypted (1.3.2) - encryptor (>= 1.3.0) - bcrypt (3.1.9) - builder (3.2.2) - celluloid (0.15.2) - timers (~> 1.1.0) - codeclimate-test-reporter (0.4.0) - simplecov (>= 0.7.1, < 1.0.0) - coderay (1.1.0) - devise (3.4.1) + addressable (2.5.1) + public_suffix (~> 2.0, >= 2.0.2) + ansi (1.5.0) + arel (6.0.4) + attr_encrypted (3.0.3) + encryptor (~> 3.0.0) + bcrypt (3.1.11) + builder (3.2.3) + codeclimate-test-reporter (1.0.8) + simplecov (<= 0.13) + coderay (1.1.1) + concurrent-ruby (1.0.5) + devise (4.3.0) bcrypt (~> 3.0) orm_adapter (~> 0.1) - railties (>= 3.2.6, < 5) + railties (>= 4.1.0, < 5.2) responders - thread_safe (~> 0.1) warden (~> 1.2.3) docile (1.1.5) - encryptor (1.3.0) + encryptor (3.0.0) erubis (2.7.0) - faker (1.4.3) + faker (1.7.3) i18n (~> 0.5) - faraday (0.9.0) + faraday (0.11.0) multipart-post (>= 1.2, < 3) - ffi (1.9.3) + faraday-http-cache (2.0.0) + faraday (~> 0.8) + ffi (1.9.18) formatador (0.2.5) fuzz_ball (0.9.1) - guard (2.6.1) + github_changelog_generator (1.14.3) + activesupport + faraday-http-cache + multi_json + octokit (~> 4.6) + rainbow (>= 2.1) + rake (>= 10.0) + retriable (~> 2.1) + globalid (0.4.0) + activesupport (>= 4.2.0) + guard (2.14.1) formatador (>= 0.2.4) - listen (~> 2.7) + listen (>= 2.7, < 4.0) lumberjack (~> 1.0) + nenv (~> 0.1) + notiffany (~> 0.0) pry (>= 0.9.12) + shellany (~> 0.0) thor (>= 0.18.1) - guard-minitest (2.3.1) - guard (~> 2.0) + guard-compat (1.2.1) + guard-minitest (2.4.6) + guard-compat (~> 1.2) minitest (>= 3.0) - hashie (3.2.0) - hike (1.2.3) - i18n (0.6.11) - json (1.8.1) - jwt (1.0.0) - listen (2.7.9) - celluloid (>= 0.15.2) - rb-fsevent (>= 0.9.3) - rb-inotify (>= 0.9) - lumberjack (1.0.9) - mail (2.6.1) - mime-types (>= 1.16, < 3) + hashie (3.5.5) + i18n (0.8.1) + json (2.1.0) + jwt (1.5.6) + listen (3.1.5) + rb-fsevent (~> 0.9, >= 0.9.4) + rb-inotify (~> 0.9, >= 0.9.7) + ruby_dep (~> 1.2) + loofah (2.0.3) + nokogiri (>= 1.5.9) + lumberjack (1.0.12) + mail (2.6.5) + mime-types (>= 1.16, < 4) + metaclass (0.0.4) method_source (0.8.2) - mime-types (2.4.2) - minitest (5.4.2) - minitest-focus (1.1.0) + mime-types (3.1) + mime-types-data (~> 3.2015) + mime-types-data (3.2016.0521) + mini_portile2 (2.1.0) + minitest (5.10.2) + minitest-focus (1.1.2) minitest (>= 4, < 6) - minitest-rails (2.1.0) - minitest (~> 5.4) + minitest-rails (2.2.1) + minitest (~> 5.7) railties (~> 4.1) - minitest-reporters (1.0.5) + minitest-reporters (1.1.14) ansi builder minitest (>= 5.0) ruby-progressbar - multi_json (1.10.1) - multi_xml (0.5.5) + mocha (1.2.1) + metaclass (~> 0.0.1) + multi_json (1.12.1) + multi_xml (0.6.0) multipart-post (2.0.0) - mysql2 (0.3.16) - oauth2 (1.0.0) - faraday (>= 0.8, < 0.10) + mysql2 (0.4.6) + nenv (0.3.0) + nokogiri (1.7.2) + mini_portile2 (~> 2.1.0) + notiffany (0.1.1) + nenv (~> 0.1) + shellany (~> 0.0) + oauth2 (1.3.1) + faraday (>= 0.8, < 0.12) jwt (~> 1.0) multi_json (~> 1.3) multi_xml (~> 0.5) - rack (~> 1.2) - omniauth (1.2.2) - hashie (>= 1.2, < 4) - rack (~> 1.0) - omniauth-oauth2 (1.2.0) - faraday (>= 0.8, < 0.10) - multi_json (~> 1.3) + rack (>= 1.2, < 3) + octokit (4.7.0) + sawyer (~> 0.8.0, >= 0.5.3) + omniauth (1.6.1) + hashie (>= 3.4.6, < 3.6.0) + rack (>= 1.6.2, < 3) + omniauth-oauth2 (1.4.0) oauth2 (~> 1.0) omniauth (~> 1.2) orm_adapter (0.5.0) - pg (0.17.1) - pry (0.10.1) + pg (0.20.0) + pry (0.10.4) coderay (~> 1.1.0) method_source (~> 0.8.1) slop (~> 3.4) pry-remote (0.1.8) pry (~> 0.9) slop (~> 3.0) - rack (1.5.2) - rack-cors (0.2.9) - rack-test (0.6.2) + public_suffix (2.0.5) + rack (1.6.8) + rack-cors (0.4.1) + rack-test (0.6.3) rack (>= 1.0) - rails (4.1.6) - actionmailer (= 4.1.6) - actionpack (= 4.1.6) - actionview (= 4.1.6) - activemodel (= 4.1.6) - activerecord (= 4.1.6) - activesupport (= 4.1.6) + rails (4.2.8) + actionmailer (= 4.2.8) + actionpack (= 4.2.8) + actionview (= 4.2.8) + activejob (= 4.2.8) + activemodel (= 4.2.8) + activerecord (= 4.2.8) + activesupport (= 4.2.8) bundler (>= 1.3.0, < 2.0) - railties (= 4.1.6) - sprockets-rails (~> 2.0) - railties (4.1.6) - actionpack (= 4.1.6) - activesupport (= 4.1.6) + railties (= 4.2.8) + sprockets-rails + rails-deprecated_sanitizer (1.0.3) + activesupport (>= 4.2.0.alpha) + rails-dom-testing (1.0.8) + activesupport (>= 4.2.0.beta, < 5.0) + nokogiri (~> 1.6) + rails-deprecated_sanitizer (>= 1.0.1) + rails-html-sanitizer (1.0.3) + loofah (~> 2.0) + railties (4.2.8) + actionpack (= 4.2.8) + activesupport (= 4.2.8) rake (>= 0.8.7) thor (>= 0.18.1, < 2.0) - rake (10.3.2) - rb-fsevent (0.9.4) - rb-inotify (0.9.5) + rainbow (2.2.2) + rake + rake (12.0.0) + rb-fsevent (0.9.8) + rb-inotify (0.9.8) ffi (>= 0.5.0) - responders (1.1.2) - railties (>= 3.2, < 4.2) - ruby-progressbar (1.5.1) - simplecov (0.9.0) + responders (2.4.0) + actionpack (>= 4.2.0, < 5.3) + railties (>= 4.2.0, < 5.3) + retriable (2.1.0) + ruby-progressbar (1.8.1) + ruby_dep (1.5.0) + sawyer (0.8.1) + addressable (>= 2.3.5, < 2.6) + faraday (~> 0.8, < 1.0) + shellany (0.0.1) + simplecov (0.13.0) docile (~> 1.1.0) - multi_json - simplecov-html (~> 0.8.0) - simplecov-html (0.8.0) + json (>= 1.8, < 3) + simplecov-html (~> 0.10.0) + simplecov-html (0.10.0) slop (3.6.0) - sprockets (2.12.2) - hike (~> 1.2) - multi_json (~> 1.0) - rack (~> 1.0) - tilt (~> 1.1, != 1.3.0) - sprockets-rails (2.1.4) - actionpack (>= 3.0) - activesupport (>= 3.0) - sprockets (~> 2.8) - sqlite3 (1.3.9) - thor (0.19.1) - thread_safe (0.3.4) - tilt (1.4.1) - timers (1.1.0) - tzinfo (1.2.2) + sprockets (3.7.1) + concurrent-ruby (~> 1.0) + rack (> 1, < 3) + sprockets-rails (3.2.0) + actionpack (>= 4.0) + activesupport (>= 4.0) + sprockets (>= 3.0.0) + sqlite3 (1.3.13) + thor (0.19.4) + thread_safe (0.3.6) + tzinfo (1.2.3) thread_safe (~> 0.1) - warden (1.2.3) + warden (1.2.7) rack (>= 1.0) PLATFORMS @@ -214,12 +268,14 @@ DEPENDENCIES faker figaro! fuzz_ball + github_changelog_generator guard guard-minitest minitest minitest-focus minitest-rails minitest-reporters + mocha mysql2 omniauth-facebook! omniauth-github! @@ -230,3 +286,6 @@ DEPENDENCIES rack-cors sqlite3 (~> 1.3) thor + +BUNDLED WITH + 1.14.6 diff --git a/README.md b/README.md index 941e8622f..2961bc362 100644 --- a/README.md +++ b/README.md @@ -8,9 +8,14 @@ ## Simple, secure token based authentication for Rails. +[![Join the chat at https://gitter.im/lynndylanhurley/devise_token_auth](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/lynndylanhurley/devise_token_auth?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) + This gem provides the following features: -* Seamless integration with the the venerable [ng-token-auth](https://github.com/lynndylanhurley/ng-token-auth) module for [angular.js](https://github.com/angular/angular.js). +* Seamless integration with: + * [ng-token-auth](https://github.com/lynndylanhurley/ng-token-auth) for [AngularJS](https://github.com/angular/angular.js) + * [Angular2-Token](https://github.com/neroniaky/angular2-token) for [Angular2](https://github.com/angular/angular) + * [jToker](https://github.com/lynndylanhurley/j-toker) for [jQuery](https://jquery.com/) * Oauth2 authentication using [OmniAuth](https://github.com/intridea/omniauth). * Email authentication using [Devise](https://github.com/plataformatec/devise), including: * User registration @@ -20,11 +25,19 @@ This gem provides the following features: * Support for [multiple user models](https://github.com/lynndylanhurley/devise_token_auth#using-multiple-models). * It is [secure](#security). -# [Live Demo](http://ng-token-auth-demo.herokuapp.com/) +# Live Demos + +[Here is a demo](http://ng-token-auth-demo.herokuapp.com/) of this app running with the [ng-token-auth](https://github.com/lynndylanhurley/ng-token-auth) module and [AngularJS](https://github.com/angular/angular.js). + +[Here is a demo](https://angular2-token.herokuapp.com) of this app running with the [Angular2-Token](https://github.com/neroniaky/angular2-token) service and [Angular2](https://github.com/angular/angular). -[Here is a demo](http://ng-token-auth-demo.herokuapp.com/) of this app running with the [ng-token-auth](https://github.com/lynndylanhurley/ng-token-auth) module. +[Here is a demo](https://j-toker-demo.herokuapp.com/) of this app using the [jToker](https://github.com/lynndylanhurley/j-toker) plugin and [React](http://facebook.github.io/react/). -The fully configured api used in the demo can be found [here](https://github.com/lynndylanhurley/devise_token_auth_demo). +The fully configured api used in these demos can be found [here](https://github.com/lynndylanhurley/devise_token_auth_demo). + +# Troubleshooting + +Please read the [issue reporting guidelines](#issue-reporting) before posting issues. # Table of Contents @@ -36,19 +49,24 @@ The fully configured api used in the demo can be found [here](https://github.com * [OmniAuth Authentication](#omniauth-authentication) * [OmniAuth Provider Settings](#omniauth-provider-settings) * [Email Authentication](#email-authentication) + * [Customizing Devise Verbiage](#customizing-devise-verbiage) * [Cross Origin Requests (CORS)](#cors) * [Usage Continued](#usage-cont) * [Mounting Routes](#mounting-routes) - * [Controller Integration](#controller-concerns) + * [Controller Integration](#controller-methods) * [Model Integration](#model-concerns) * [Using Multiple User Classes](#using-multiple-models) - * [Skip Confirmation Upon Email Registration](#skip-confirmation-upon-registration) + * [Excluding Modules](#excluding-modules) * [Custom Controller Overrides](#custom-controller-overrides) + * [Passing blocks to Controllers](#passing-blocks-controllers) * [Email Template Overrides](#email-template-overrides) +* [Issue Reporting Guidelines](#issue-reporting) +* [FAQ](#faq) * [Conceptual Diagrams](#conceptual) * [Token Management](#about-token-management) * [Batch Requests](#about-batch-requests) * [Security](#security) +* [Callouts](#callouts) * [Contribution Guidelines](#contributing) # Dependencies @@ -72,7 +90,7 @@ bundle install # Configuration TL;DR -You will need to create a [user model](#model-concerns), [define routes](#mounting-routes), [include concerns](#controller-concerns), and you may want to alter some of the [default settings](#initializer-settings) for this gem. Run the following command for an easy one-step installation: +You will need to create a [user model](#model-concerns), [define routes](#mounting-routes), [include concerns](#controller-methods), and you may want to alter some of the [default settings](#initializer-settings) for this gem. Run the following command for an easy one-step installation: ~~~bash rails g devise_token_auth:install [USER_CLASS] [MOUNT_PATH] @@ -81,7 +99,7 @@ rails g devise_token_auth:install [USER_CLASS] [MOUNT_PATH] **Example**: ~~~bash -rails g devise_token_auth:install User /auth +rails g devise_token_auth:install User auth ~~~ This generator accepts the following optional arguments: @@ -89,7 +107,7 @@ This generator accepts the following optional arguments: | Argument | Default | Description | |---|---|---| | USER_CLASS | `User` | The name of the class to use for user authentication. | -| MOUNT_PATH | `/auth` | The path at which to mount the authentication routes. [Read more](#usage). | +| MOUNT_PATH | `auth` | The path at which to mount the authentication routes. [Read more](#usage-tldr). | The following events will take place when using the install generator: @@ -99,7 +117,7 @@ The following events will take place when using the install generator: * Routes will be appended to file at `config/routes.rb`. [Read more](#mounting-routes). -* A concern will be included by your application controller at `app/controllers/application_controller.rb`. [Read more](#controller-concerns). +* A concern will be included by your application controller at `app/controllers/application_controller.rb`. [Read more](#controller-methods). * A migration file will be created in the `db/migrate` directory. Inspect the migrations file, add additional columns if necessary, and then run the migration: @@ -118,20 +136,20 @@ You may also need to configure the following items: # Usage TL;DR -The following routes are available for use by your client. These routes live relative to the path at which this engine is mounted (`/auth` by default). These routes correspond to the defaults used by the [ng-token-auth](https://github.com/lynndylanhurley/ng-token-auth) module for angular.js. +The following routes are available for use by your client. These routes live relative to the path at which this engine is mounted (`auth` by default). These routes correspond to the defaults used by the [ng-token-auth](https://github.com/lynndylanhurley/ng-token-auth) module for [AngularJS](https://angularjs.org/) and the [jToker](https://github.com/lynndylanhurley/j-toker) plugin for [jQuery](https://jquery.com/). | path | method | purpose | |:-----|:-------|:--------| -| / | POST | Email registration. Accepts **`email`**, **`password`**, and **`password_confirmation`** params. A verification email will be sent to the email address provided. Accepted params can be customized using the [`devise_parameter_sanitizer`](https://github.com/plataformatec/devise#strong-parameters) system. | -| / | DELETE | Account deletion. This route will destroy users identified by their **`uid`** and **`auth_token`** headers. | -| / | PUT | Account updates. This route will update an existing user's account settings. The default accepted params are **`password`** and **`password_confirmation`**, but this can be customized using the [`devise_parameter_sanitizer`](https://github.com/plataformatec/devise#strong-parameters) system. | -| /sign_in | POST | Email authentication. Accepts **`email`** and **`password`** as params. This route will return a JSON representation of the `User` model on successful login. | -| /sign_out | DELETE | Use this route to end the user's current session. This route will invalidate the user's authentication token. | +| / | POST | Email registration. Requires **`email`**, **`password`**, and **`password_confirmation`** params. A verification email will be sent to the email address provided. Accepted params can be customized using the [`devise_parameter_sanitizer`](https://github.com/plataformatec/devise#strong-parameters) system. | +| / | DELETE | Account deletion. This route will destroy users identified by their **`uid`**, **`access_token`** and **`client`** headers. | +| / | PUT | Account updates. This route will update an existing user's account settings. The default accepted params are **`password`** and **`password_confirmation`**, but this can be customized using the [`devise_parameter_sanitizer`](https://github.com/plataformatec/devise#strong-parameters) system. If **`config.check_current_password_before_update`** is set to `:attributes` the **`current_password`** param is checked before any update, if it is set to `:password` the **`current_password`** param is checked only if the request updates user password. | +| /sign_in | POST | Email authentication. Requires **`email`** and **`password`** as params. This route will return a JSON representation of the `User` model on successful login along with the `access-token` and `client` in the header of the response. | +| /sign_out | DELETE | Use this route to end the user's current session. This route will invalidate the user's authentication token. You must pass in **`uid`**, **`client`**, and **`access-token`** in the request headers. | | /:provider | GET | Set this route as the destination for client authentication. Ideally this will happen in an external window or popup. [Read more](#omniauth-authentication). | | /:provider/callback | GET/POST | Destination for the oauth2 provider's callback uri. `postMessage` events containing the authenticated user's data will be sent back to the main client window from this page. [Read more](#omniauth-authentication). | -| /validate_token | POST | Use this route to validate tokens on return visits to the client. Accepts **`uid`** and **`auth_token`** as params. These values should correspond to the columns in your `User` table of the same names. | +| /validate_token | GET | Use this route to validate tokens on return visits to the client. Requires **`uid`**, **`client`**, and **`access-token`** as params. These values should correspond to the columns in your `User` table of the same names. | | /password | POST | Use this route to send a password reset confirmation email to users that registered by email. Accepts **`email`** and **`redirect_url`** as params. The user matching the `email` param will be sent instructions on how to reset their password. `redirect_url` is the url to which the user will be redirected after visiting the link contained in the email. | -| /password | PUT | Use this route to change users' passwords. Accepts **`password`** and **`password_confirmation`** as params. This route is only valid for users that registered by email (OAuth2 users will receive an error). | +| /password | PUT | Use this route to change users' passwords. Requires **`password`** and **`password_confirmation`** as params. This route is only valid for users that registered by email (OAuth2 users will receive an error). It also checks **`current_password`** if **`config.check_current_password_before_update`** is not set `false` (disabled by default). | | /password/edit | GET | Verify user by password reset token. This route is the destination URL for password reset confirmation. This route must contain **`reset_password_token`** and **`redirect_url`** params. These values will be set automatically by the confirmation email that is generated by the password reset request. | [Jump here](#usage-cont) for more usage information. @@ -144,11 +162,32 @@ The following settings are available for configuration in `config/initializers/d | Name | Default | Description| |---|---|---| -| **`change_headers_on_each_request`** | `true` | By default the access_token header will change after each request. The client is responsible for keeping track of the changing tokens. The [ng-token-auth](https://github.com/lynndylanhurley/ng-token-auth) module for angular.js does this out of the box. While this implementation is more secure, it can be difficult to manage. Set this to false to prevent the `access_token` header from changing after each request. [Read more](#about-token-management). | +| **`change_headers_on_each_request`** | `true` | By default the access-token header will change after each request. The client is responsible for keeping track of the changing tokens. Both [ng-token-auth](https://github.com/lynndylanhurley/ng-token-auth) and [jToker](https://github.com/lynndylanhurley/j-toker) do this out of the box. While this implementation is more secure, it can be difficult to manage. Set this to false to prevent the `access-token` header from changing after each request. [Read more](#about-token-management). | | **`token_lifespan`** | `2.weeks` | Set the length of your tokens' lifespans. Users will need to re-authenticate after this duration of time has passed since their last login. | | **`batch_request_buffer_throttle`** | `5.seconds` | Sometimes it's necessary to make several requests to the API at the same time. In this case, each request in the batch will need to share the same auth token. This setting determines how far apart the requests can be while still using the same auth token. [Read more](#about-batch-requests). | | **`omniauth_prefix`** | `"/omniauth"` | This route will be the prefix for all oauth2 redirect callbacks. For example, using the default '/omniauth' setting, the github oauth2 provider will redirect successful authentications to '/omniauth/github/callback'. [Read more](#omniauth-provider-settings). | +| **`default_confirm_success_url`** | `nil` | By default this value is expected to be sent by the client so that the API knows where to redirect users after successful email confirmation. If this param is set, the API will redirect to this value when no value is provided by the client. | +| **`default_password_reset_url`** | `nil` | By default this value is expected to be sent by the client so that the API knows where to redirect users after successful password resets. If this param is set, the API will redirect to this value when no value is provided by the client. | +| **`redirect_whitelist`** | `nil` | As an added security measure, you can limit the URLs to which the API will redirect after email token validation (password reset, email confirmation, etc.). This value should be an array containing matches to the client URLs to be visited after validation. Wildcards are supported. | +| **`enable_standard_devise_support`** | `false` | By default, only Bearer Token authentication is implemented out of the box. If, however, you wish to integrate with legacy Devise authentication, you can do so by enabling this flag. NOTE: This feature is highly experimental! | +| **`remove_tokens_after_password_reset`** | `false` | By default, old tokens are not invalidated when password is changed. Enable this option if you want to make passwords updates to logout other devices. | +| **`default_callbacks`** | `true` | By default User model will include the `DeviseTokenAuth::Concerns::UserOmniauthCallbacks` concern, which has `email`, `uid` validations & `uid` synchronization callbacks. | + +Additionally, you can configure other aspects of devise by manually creating the traditional devise.rb file at `config/initializers/devise.rb`. Here are some examples of what you can do in this file: + +~~~ruby +Devise.setup do |config| + # The e-mail address that mail will appear to be sent from + # If absent, mail is sent from "please-change-me-at-config-initializers-devise@example.com" + config.mailer_sender = "support@myapp.com" + + # If using rails-api, you may want to tell devise to not use ActionDispatch::Flash + # middleware b/c rails-api does not include it. + # See: http://stackoverflow.com/q/19600905/806956 + config.navigational_formats = [:json] +end +~~~ ## OmniAuth authentication @@ -198,7 +237,7 @@ For example, given that the app is mounted using the following settings: ~~~ruby # config/routes.rb -mount_devise_token_auth_for 'User', at: '/auth' +mount_devise_token_auth_for 'User', at: 'auth' ~~~ The client configuration for github should look like this: @@ -216,6 +255,17 @@ angular.module('myApp', ['ng-token-auth']) }); ~~~ +**jToker settings for github should look like this: + +~~~javascript +$.auth.configure({ + apiUrl: 'http://api.example.com', + authProviderPaths: { + github: '/auth/github' // <-- note that this is different than what was set with github + } +}); +~~~ + This incongruence is necessary to support multiple user classes and mounting points. #### Note for [pow](http://pow.cx/) and [xip.io](http://xip.io) users @@ -247,6 +297,21 @@ Rails.application.configure do end ~~~ +If you wish to send custom e-mails instead of using the default devise templates, you can [do that too](#email-template-overrides). + +## Customizing Devise Verbiage +Devise Token Auth ships with intelligent default wording for everything you need. But that doesn't mean you can't make it more awesome. You can override the [devise defaults](https://github.com/plataformatec/devise/blob/master/config/locales/en.yml) by creating a YAML file at `config/locales/devise.en.yml` and assigning whatever custom values you want. For example, to customize the subject line of your devise e-mails, you could do this: + +~~~yaml +en: + devise: + mailer: + confirmation_instructions: + subject: "Please confirm your e-mail address" + reset_password_instructions: + subject: "Reset password request" +~~~ + ## CORS If your API and client live on different domains, you will need to configure your Rails API to allow [cross origin requests](http://en.wikipedia.org/wiki/Cross-origin_resource_sharing). The [rack-cors](https://github.com/cyu/rack-cors) gem can be used to accomplish this. @@ -276,7 +341,7 @@ end Make extra sure that the `Access-Control-Expose-Headers` includes `access-token`, `expiry`, `token-type`, `uid`, and `client` (as is set in the example above by the`:expose` param). If your client experiences erroneous 401 responses, this is likely the cause. -CORS may not be possible with older browsers (IE8, IE9). I usually set up a proxy for those browsers. See the [ng-token-auth readme](https://github.com/lynndylanhurley/ng-token-auth) for more information. +CORS may not be possible with older browsers (IE8, IE9). I usually set up a proxy for those browsers. See the [ng-token-auth readme](https://github.com/lynndylanhurley/ng-token-auth) or the [jToker readme](https://github.com/lynndylanhurley/j-toker) for more information. # Usage cont. @@ -289,17 +354,17 @@ The authentication routes must be mounted to your project. This gem includes a r | Argument | Type | Default | Description | |---|---|---|---| |`class_name`| string | 'User' | The name of the class to use for authentication. This class must include the [model concern described here](#model-concerns). | -| `options` | object | {at: '/auth'} | The [routes to be used for authentication](#usage) will be prefixed by the path specified in the `at` param of this object. | +| `options` | object | {at: 'auth'} | The [routes to be used for authentication](#usage) will be prefixed by the path specified in the `at` param of this object. | **Example**: ~~~ruby # config/routes.rb -mount_devise_token_auth_for 'User', at: '/auth' +mount_devise_token_auth_for 'User', at: 'auth' ~~~ Any model class can be used, but the class will need to include [`DeviseTokenAuth::Concerns::User`](#model-concerns) for authentication to work properly. -You can mount this engine to any route that you like. `/auth` is used by default to conform with the defaults of the [ng-token-auth](https://github.com/lynndylanhurley/ng-token-auth) module. +You can mount this engine to any route that you like. `/auth` is used by default to conform with the defaults of the [ng-token-auth](https://github.com/lynndylanhurley/ng-token-auth) module and the [jToker](https://github.com/lynndylanhurley/j-toker) plugin. ## Controller Methods @@ -344,7 +409,7 @@ Note that if the model that you're trying to access isn't called `User`, the hel # app/controllers/test_controller.rb class TestController < ApplicationController before_action :authenticate_user! - + def members_only render json: { data: { @@ -362,8 +427,8 @@ The authentication information should be included by the client in the headers o ##### Authentication headers example: ~~~ -"access_token": "wwwww", -"token_type": "Bearer", +"access-token": "wwwww", +"token-type": "Bearer", "client": "xxxxx", "expiry": "yyyyy", "uid": "zzzzz" @@ -373,18 +438,18 @@ The authentication headers consists of the following params: | param | description | |---|---| -| **`access_token`** | This serves as the user's password for each request. A hashed version of this value is stored in the database for later comparison. This value should be changed on each request. | +| **`access-token`** | This serves as the user's password for each request. A hashed version of this value is stored in the database for later comparison. This value should be changed on each request. | | **`client`** | This enables the use of multiple simultaneous sessions on different clients. (For example, a user may want to be authenticated on both their phone and their laptop at the same time.) | | **`expiry`** | The date at which the current session will expire. This can be used by clients to invalidate expired tokens without the need for an API request. | | **`uid`** | A unique value that is used to identify the user. This is necessary because searching the DB for users by their access token will make the API susceptible to [timing attacks](http://codahale.com/a-lesson-in-timing-attacks/). | -The authentication headers required for each request will be available in the response from the previous request. If you are using the [ng-token-auth](https://github.com/lynndylanhurley/ng-token-auth) module for angular.js, this functionality is already provided. +The authentication headers required for each request will be available in the response from the previous request. If you are using the [ng-token-auth](https://github.com/lynndylanhurley/ng-token-auth) AngularJS module or the [jToker](https://github.com/lynndylanhurley/j-toker) jQuery plugin, this functionality is already provided. ## Model Concerns ##### DeviseTokenAuth::Concerns::User -Typical use of this gem will not require the use of any of the following model methods. All authentication should be handled invisibly by the [controller concerns](#controller-concerns) described above. +Typical use of this gem will not require the use of any of the following model methods. All authentication should be handled invisibly by the [controller concerns](#controller-methods) described above. Models that include the `DeviseTokenAuth::Concerns::User` concern will have access to the following public methods (read the above section for context on `token` and `client`): @@ -394,9 +459,9 @@ Models that include the `DeviseTokenAuth::Concerns::User` concern will have acce ~~~ruby # extract token + client_id from auth header client_id = request.headers['client'] - token = request.headers['access_token'] + token = request.headers['access-token'] - @user.valid_token?(token, client_id) + @resource.valid_token?(token, client_id) ~~~ * **`create_new_auth_token`**: creates a new auth token with all of the necessary metadata. Accepts `client` as an optional argument. Will generate a new `client` if none is provided. Returns the authentication headers that should be sent by the client as an object. @@ -407,7 +472,7 @@ Models that include the `DeviseTokenAuth::Concerns::User` concern will have acce client_id = request.headers['client'] # update token, generate updated auth headers for response - new_auth_header = @user.create_new_auth_token(client_id) + new_auth_header = @resource.create_new_auth_token(client_id) # update response with the header that will be required by the next request response.headers.merge!(new_auth_header) @@ -422,13 +487,13 @@ Models that include the `DeviseTokenAuth::Concerns::User` concern will have acce token = SecureRandom.urlsafe_base64(nil, false) # store client + token in user's token hash - @user.tokens[client_id] = { + @resource.tokens[client_id] = { token: BCrypt::Password.create(token), expiry: (Time.now + DeviseTokenAuth.token_lifespan).to_i } # generate auth headers for response - new_auth_header = @user.build_auth_header(token, client_id) + new_auth_header = @resource.build_auth_header(token, client_id) # update response with the header that will be required by the next request response.headers.merge!(new_auth_header) @@ -436,7 +501,11 @@ Models that include the `DeviseTokenAuth::Concerns::User` concern will have acce ## Using multiple models -### [View Live Multi-User Demo](http://ng-token-auth-demo.herokuapp.com/multi-user) +### View Live Multi-User Demos + +* [AngularJS](http://ng-token-auth-demo.herokuapp.com/multi-user) +* [Angular2](https://angular2-token.herokuapp.com) +* [React + jToker](http://j-toker-demo.herokuapp.com/#/alt-user) This gem supports the use of multiple user models. One possible use case is to authenticate visitors using a model called `User`, and to authenticate administrators with a model called `Admin`. Take the following steps to add another authentication model to your app: @@ -450,6 +519,7 @@ This gem supports the use of multiple user models. One possible use case is to a 1. Define the routes to be used by the `Admin` user within a [`devise_scope`](https://github.com/plataformatec/devise#configuring-routes). **Example**: + ~~~ruby Rails.application.routes.draw do # when using multiple models, controllers will default to the first available @@ -457,11 +527,11 @@ This gem supports the use of multiple user models. One possible use case is to a # within a `devise_scope` block # define :users as the first devise mapping: - mount_devise_token_auth_for 'User', at: '/auth' + mount_devise_token_auth_for 'User', at: 'auth' # define :admins as the second devise mapping. routes using this class will # need to be defined within a devise_scope as shown below - mount_devise_token_auth_for "Admin", at: '/admin_auth' + mount_devise_token_auth_for "Admin", at: 'admin_auth' # this route will authorize requests using the User class get 'demo/members_only', to: 'demo#members_only' @@ -472,9 +542,9 @@ This gem supports the use of multiple user models. One possible use case is to a end end ~~~ - + 1. Configure any `Admin` restricted controllers. Controllers will now have access to the methods [described here](#methods): - * `before_action: :authenticate_admin!` + * `before_action :authenticate_admin!` * `current_admin` * `admin_signed_in?` @@ -489,7 +559,7 @@ It is also possible to control access to multiple user types at the same time us class DemoGroupController < ApplicationController devise_token_auth_group :member, contains: [:user, :admin] before_action :authenticate_member! - + def members_only render json: { data: { @@ -507,28 +577,71 @@ In the above example, the following methods will be available (in addition to `c * `current_member` * `member_signed_in?` -## Skip Confirmation Upon Email Registration +## Excluding Modules -By default, an email is sent containing a link that the user must visit to activate their account. This measure is in place to ensure that users cannot register other people for accounts. +By default, almost all of the Devise modules are included: +* [`database_authenticatable`](https://github.com/plataformatec/devise/blob/master/lib/devise/models/database_authenticatable.rb) +* [`registerable`](https://github.com/plataformatec/devise/blob/master/lib/devise/models/registerable.rb) +* [`recoverable`](https://github.com/plataformatec/devise/blob/master/lib/devise/models/recoverable.rb) +* [`trackable`](https://github.com/plataformatec/devise/blob/master/lib/devise/models/trackable.rb) +* [`validatable`](https://github.com/plataformatec/devise/blob/master/lib/devise/models/validatable.rb) +* [`confirmable`](https://github.com/plataformatec/devise/blob/master/lib/devise/models/confirmable.rb) +* [`omniauthable`](https://github.com/plataformatec/devise/blob/master/lib/devise/models/omniauthable.rb) -To bypass this measure, add `before_create :skip_confirmation!` to your `User` model (or equivalent). +You may not want all of these features enabled in your app. That's OK! You can mix and match to suit your own unique style. -##### Example: bypass email confirmation +The following example shows how to disable email confirmation. + +##### Example: disable email confirmation + +Just list the devise modules that you want to include **before** including the `DeviseTokenAuth::Concerns::User` model concern. + +~~~ruby +# app/models/user.rb +class User < ActiveRecord::Base + + # notice this comes BEFORE the include statement below + # also notice that :confirmable is not included in this block + devise :database_authenticatable, :recoverable, + :trackable, :validatable, :registerable, + :omniauthable + + # note that this include statement comes AFTER the devise block above + include DeviseTokenAuth::Concerns::User +end +~~~ + +Some features include routes that you may not want mounted to your app. The following example shows how to disable OAuth and its routes. + +##### Example: disable OAuth authentication + +First instruct the model not to include the `omniauthable` module. ~~~ruby +# app/models/user.rb class User < ActiveRecord::Base + + # notice that :omniauthable is not included in this block + devise :database_authenticatable, :confirmable, + :recoverable, :trackable, :validatable, + :registerable + include DeviseTokenAuth::Concerns::User - before_create :skip_confirmation! end ~~~ -##### Note for ng-token-auth users: +Now tell the route helper to `skip` mounting the `omniauth_callbacks` controller: -If this `before_create :skip_confirmation!` callback is in place, the `$auth.submitRegistration` method will both register and authenticate users in a single step. +~~~ruby +Rails.application.routes.draw do + # config/routes.rb + mount_devise_token_auth_for 'User', at: 'auth', skip: [:omniauth_callbacks] +end +~~~ ## Custom Controller Overrides -The built-in controllers can be overridden with your own custom controllers. +The built-in controllers can be overridden with your own custom controllers. For example, the default behavior of the [`validate_token`](https://github.com/lynndylanhurley/devise_token_auth/blob/8a33d25deaedb4809b219e557e82ec7ec61bf940/app/controllers/devise_token_auth/token_validations_controller.rb#L6) method of the [`TokenValidationController`](https://github.com/lynndylanhurley/devise_token_auth/blob/8a33d25deaedb4809b219e557e82ec7ec61bf940/app/controllers/devise_token_auth/token_validations_controller.rb) is to return the `User` object as json (sans password and token data). The following example shows how to override the `validate_token` action to include a model method as well. @@ -537,8 +650,8 @@ For example, the default behavior of the [`validate_token`](https://github.com/l ~~~ruby # config/routes.rb Rails.application.routes.draw do - ... - mount_devise_token_auth_for 'User', at: '/auth', controllers: { + ... + mount_devise_token_auth_for 'User', at: 'auth', controllers: { token_validations: 'overrides/token_validations' } end @@ -548,10 +661,10 @@ module Overrides class TokenValidationsController < DeviseTokenAuth::TokenValidationsController def validate_token - # @user will have been set by set_user_by_token concern - if @user + # @resource will have been set by set_user_by_token concern + if @resource render json: { - data: @user.as_json(methods: :calculate_operating_thetan) + data: @resource.as_json(methods: :calculate_operating_thetan) } else render json: { @@ -564,10 +677,49 @@ module Overrides end ~~~ +## Overriding rendering methods +To customize json rendering, implement the following protected controller methods, for success methods, assume that the @resource object is available: + +### Registrations Controller +* render_create_error_missing_confirm_success_url +* render_create_error_redirect_url_not_allowed +* render_create_success +* render_create_error +* render_create_error_email_already_exists +* render_update_success +* render_update_error +* render_update_error_user_not_found + + +### Sessions Controller +* render_new_error +* render_create_success +* render_create_error_not_confirmed +* render_create_error_bad_credentials +* render_destroy_success +* render_destroy_error + + +### Passwords Controller +* render_create_error_missing_email +* render_create_error_missing_redirect_url +* render_create_error_not_allowed_redirect_url +* render_create_success +* render_create_error +* render_update_error_unauthorized +* render_update_error_password_not_required +* render_update_error_missing_password +* render_update_success +* render_update_error + +### Token Validations Controller +* render_validate_token_success +* render_validate_token_error + ##### Example: all :controller options with default settings: ~~~ruby -mount_devise_token_auth_for 'User', at: '/auth', controllers: { +mount_devise_token_auth_for 'User', at: 'auth', controllers: { confirmations: 'devise_token_auth/confirmations', passwords: 'devise_token_auth/passwords', omniauth_callbacks: 'devise_token_auth/omniauth_callbacks', @@ -579,6 +731,24 @@ mount_devise_token_auth_for 'User', at: '/auth', controllers: { **Note:** Controller overrides must implement the expected actions of the controllers that they replace. +## Passing blocks to Controllers + +It may be that you simply want to _add_ behavior to existing controllers without having to re-implement their behavior completely. In this case, you can do so by creating a new controller that inherits from any of DeviseTokenAuth's controllers, overriding whichever methods you'd like to add behavior to by passing a block to `super`: + +```ruby +class Custom::RegistrationsController < DeviseTokenAuth::RegistrationsController + + def create + super do |resource| + resource.do_something(extra) + end + end + +end +``` + +Your block will be performed just before the controller would usually render a successful response. + ## Email Template Overrides You will probably want to override the default email templates for email sign-up and password-reset confirmation. Run the following command to copy the email templates into your app: @@ -592,10 +762,77 @@ This will create two new files: * `app/views/devise/mailer/reset_password_instructions.html.erb` * `app/views/devise/mailer/confirmation_instructions.html.erb` -These files may be edited to suit your taste. +These files may be edited to suit your taste. You can customize the e-mail subjects like [this](#customizing-devise-verbiage). **Note:** if you choose to modify these templates, do not modify the `link_to` blocks unless you absolutely know what you are doing. +# Issue Reporting + +When posting issues, please include the following information to speed up the troubleshooting process: + +* **Version**: which version of this gem (and [ng-token-auth](https://github.com/lynndylanhurley/ng-token-auth), [jToker](https://github.com/lynndylanhurley/j-toker) or [Angular2-Token](https://github.com/neroniaky/angular2-token) if applicable) are you using? +* **Request and response headers**: these can be found in the "Network" tab of your browser's web inspector. +* **Rails Stacktrace**: this can be found in the `log/development.log` of your API. +* **Environmental Info**: How is your application different from the [reference implementation](https://github.com/lynndylanhurley/devise_token_auth_demo)? This may include (but is not limited to) the following details: + * **Routes**: are you using some crazy namespace, scope, or constraint? + * **Gems**: are you using MongoDB, Grape, RailsApi, ActiveAdmin, etc.? + * **Custom Overrides**: what have you done in terms of [custom controller overrides](#custom-controller-overrides)? + * **Custom Frontend**: are you using [ng-token-auth](https://github.com/lynndylanhurley/ng-token-auth), [jToker](https://github.com/lynndylanhurley/j-toker), [Angular2-Token](https://github.com/neroniaky/angular2-token), or something else? + +# FAQ + +### Can I use this gem alongside standard Devise? + +Yes! But you will need to enable the support of separate routes for standard Devise. So do something like this: + +#### config/initializers/devise_token_auth.rb +~~~ruby +DeviseTokenAuth.setup do |config| + # config.enable_standard_devise_support = false +end +~~~ + +#### config/routes.rb +~~~ruby +Rails.application.routes.draw do + + # standard devise routes available at /users + # NOTE: make sure this comes first!!! + devise_for :users + + # token auth routes available at /api/v1/auth + namespace :api do + scope :v1 do + mount_devise_token_auth_for 'User', at: 'auth' + end + end + +end +~~~ + +### Why are the `new` routes included if this gem doesn't use them? + +Removing the `new` routes will require significant modifications to devise. If the inclusion of the `new` routes is causing your app any problems, post an issue in the issue tracker and it will be addressed ASAP. + +### I'm having trouble using this gem alongside [ActiveAdmin](http://activeadmin.info/)... + +For some odd reason, [ActiveAdmin](http://activeadmin.info/) extends from your own app's `ApplicationController`. This becomes a problem if you include the `DeviseTokenAuth::Concerns::SetUserByToken` concern in your app's `ApplicationController`. + +The solution is to use two separate `ApplicationController` classes - one for your API, and one for ActiveAdmin. Something like this: + +~~~ruby +# app/controllers/api_controller.rb +# API routes extend from this controller +class ApiController < ActionController::Base + include DeviseTokenAuth::Concerns::SetUserByToken +end + +# app/controllers/application_controller.rb +# leave this for ActiveAdmin, and any other non-api routes +class ApplicationController < ActionController::Base +end +~~~ + # Conceptual None of the following information is required to use this gem, but read on if you're curious. @@ -606,7 +843,7 @@ Tokens should be invalidated after each request to the API. The following diagra ![password reset flow](https://github.com/lynndylanhurley/ng-token-auth/raw/master/test/app/images/flow/token-update-detail.jpg) -During each request, a new token is generated. The `access_token` header that should be used in the next request is returned in the `access_token` header of the response to the previous request. The last request in the diagram fails because it tries to use a token that was invalidated by the previous request. +During each request, a new token is generated. The `access-token` header that should be used in the next request is returned in the `access-token` header of the response to the previous request. The last request in the diagram fails because it tries to use a token that was invalidated by the previous request. The only case where an expired token is allowed is during [batch requests](#about-batch-requests). @@ -614,7 +851,7 @@ These measures are taken by default when using this gem. ## About batch requests -By default, the API should update the auth token for each request ([read more](#about-token-management)). But sometimes it's neccessary to make several concurrent requests to the API, for example: +By default, the API should update the auth token for each request ([read more](#about-token-management)). But sometimes it's necessary to make several concurrent requests to the API, for example: #####Batch request example ~~~javascript @@ -632,7 +869,7 @@ $scope.getResourceData = function() { }; ~~~ -In this case, it's impossible to update the `access_token` header for the second request with the `access_token` header of the first response because the second request will begin before the first one is complete. The server must allow these batches of concurrent requests to share the same auth token. This diagram illustrates how batch requests are identified by the server: +In this case, it's impossible to update the `access-token` header for the second request with the `access-token` header of the first response because the second request will begin before the first one is complete. The server must allow these batches of concurrent requests to share the same auth token. This diagram illustrates how batch requests are identified by the server: ![batch request overview](https://github.com/lynndylanhurley/ng-token-auth/raw/master/test/app/images/flow/batch-request-overview.jpg) @@ -652,7 +889,7 @@ This gem automatically manages batch requests. You can change the time buffer fo This gem takes the following steps to ensure security. This gem uses auth tokens that are: -* [changed after every request](#about-token-management), +* [changed after every request](#about-token-management) (can be [turned off](https://github.com/lynndylanhurley/devise_token_auth/#initializer-settings)), * [of cryptographic strength](http://ruby-doc.org/stdlib-2.1.0/libdoc/securerandom/rdoc/SecureRandom.html), * hashed using [BCrypt](https://github.com/codahale/bcrypt-ruby) (not stored in plain-text), * securely compared (to protect against timing attacks), @@ -664,6 +901,20 @@ This gem further mitigates timing attacks by using [this technique](https://gist But the most important step is to use HTTPS. You are on the hook for that. +# Callouts + +Thanks to the following contributors: + +* [@booleanbetrayal](https://github.com/booleanbetrayal) +* [@guilhermesimoes](https://github.com/guilhermesimoes) +* [@jasonswett](https://github.com/jasonswett) +* [@m2omou](https://github.com/m2omou) +* [@smarquez1](https://github.com/smarquez1) +* [@jartek](https://github.com/jartek) +* [@nicolas-besnard](https://github.com/nicolas-besnard) +* [@tbloncar](https://github.com/tbloncar) +* [@nickL](https://github.com/nickL) +* [@mchavarriagam](https://github.com/mchavarriagam) # Contributing @@ -680,9 +931,17 @@ To run the test suite do the following: 2. Run `bundle install` 3. Run `rake db:migrate` 4. Run `RAILS_ENV=test rake db:migrate` -5. Run `guard`. +5. Run `guard` The last command will open the [guard](https://github.com/guard/guard) test-runner. Guard will re-run each test suite when changes are made to its corresponding files. +To run just one test: + +1. Clone this repo +2. Run `bundle install` +3. Run `rake db:migrate` +4. Run `RAILS_ENV=test rake db:migrate` +5. See this link for various ways to run a single file or a single test: http://flavio.castelli.name/2010/05/28/rails_execute_single_test/ + # License This project uses the WTFPL diff --git a/app/controllers/devise_token_auth/application_controller.rb b/app/controllers/devise_token_auth/application_controller.rb index b48b4f64c..bd1dea58b 100644 --- a/app/controllers/devise_token_auth/application_controller.rb +++ b/app/controllers/devise_token_auth/application_controller.rb @@ -1,8 +1,27 @@ module DeviseTokenAuth class ApplicationController < DeviseController include DeviseTokenAuth::Concerns::SetUserByToken - respond_to :json + def resource_data(opts={}) + response_data = opts[:resource_json] || @resource.as_json + if is_json_api + response_data['type'] = @resource.class.name.parameterize + end + response_data + end + + def resource_errors + return @resource.errors.to_hash.merge(full_messages: @resource.errors.full_messages) + end + + protected + + def params_for_resource(resource) + devise_parameter_sanitizer.instance_values['permitted'][resource].each do |type| + params[type.to_s] ||= request.headers[type.to_s] unless request.headers[type.to_s].nil? + end + devise_parameter_sanitizer.instance_values['permitted'][resource] + end def resource_class(m=nil) if m @@ -13,5 +32,14 @@ def resource_class(m=nil) mapping.to end + + def is_json_api + return false unless defined?(ActiveModel::Serializer) + return ActiveModel::Serializer.setup do |config| + config.adapter == :json_api + end if ActiveModel::Serializer.respond_to?(:setup) + return ActiveModelSerializers.config.adapter == :json_api + end + end end diff --git a/app/controllers/devise_token_auth/concerns/set_user_by_token.rb b/app/controllers/devise_token_auth/concerns/set_user_by_token.rb index 87bc41df3..80891a322 100644 --- a/app/controllers/devise_token_auth/concerns/set_user_by_token.rb +++ b/app/controllers/devise_token_auth/concerns/set_user_by_token.rb @@ -7,14 +7,76 @@ module DeviseTokenAuth::Concerns::SetUserByToken after_action :update_auth_header end + protected + # keep track of request duration def set_request_start @request_started_at = Time.now + @used_auth_by_token = true end # user auth def set_user_by_token(mapping=nil) + # determine target authentication class + rc = resource_class(mapping) + + # no default user defined + return unless rc + + #gets the headers names, which was set in the initialize file + uid_name = DeviseTokenAuth.headers_names[:'uid'] + access_token_name = DeviseTokenAuth.headers_names[:'access-token'] + client_name = DeviseTokenAuth.headers_names[:'client'] + + # parse header for values necessary for authentication + uid = request.headers[uid_name] || params[uid_name] + @token ||= request.headers[access_token_name] || params[access_token_name] + @client_id ||= request.headers[client_name] || params[client_name] + + # client_id isn't required, set to 'default' if absent + @client_id ||= 'default' + + # check for an existing user, authenticated via warden/devise, if enabled + if DeviseTokenAuth.enable_standard_devise_support + devise_warden_user = warden.user(rc.to_s.underscore.to_sym) + if devise_warden_user && devise_warden_user.tokens[@client_id].nil? + @used_auth_by_token = false + @resource = devise_warden_user + @resource.create_new_auth_token + end + end + + # user has already been found and authenticated + return @resource if @resource && @resource.class == rc + # ensure we clear the client_id + if !@token + @client_id = nil + return + end + + return false unless @token + + # mitigate timing attacks by finding by uid instead of auth token + user = uid && rc.find_by(uid: uid) + + if user && user.valid_token?(@token, @client_id) + # sign_in with bypass: true will be deprecated in the next version of Devise + if self.respond_to? :bypass_sign_in + bypass_sign_in(user, scope: :user) + else + sign_in(:user, user, store: false, bypass: true) + end + return @resource = user + else + # zero all values previously set values + @client_id = nil + return @resource = nil + end + end + + # user auth + def set_user_by_external_token(mapping=nil) # determine target authentication class rc = resource_class(mapping) @@ -37,8 +99,8 @@ def set_user_by_token(mapping=nil) # mitigate timing attacks by finding by uid instead of auth token user = uid && rc.find_by_uid(uid) - if user && user.valid_token?(@token, @client_id) - sign_in(:user, user, store: false, bypass: true) + if user && user.valid_external_token?(@token, @client_id) + #sign_in(:user, user, store: false, bypass: true) return @resource = user else # zero all values previously set values @@ -48,40 +110,53 @@ def set_user_by_token(mapping=nil) def update_auth_header - # cannot save object if model has invalid params - return unless @resource and @resource.valid? and @client_id + return unless @resource && @resource.valid? && @client_id - # Lock the user record during any auth_header updates to ensure - # we don't have write contention from multiple threads - @resource.with_lock do + # Generate new client_id with existing authentication + @client_id = nil unless @used_auth_by_token - # determine batch request status after request processing, in case - # another processes has updated it during that processing - @is_batch_request = is_batch_request?(@resource, @client_id) + if @used_auth_by_token && !DeviseTokenAuth.change_headers_on_each_request + # should not append auth header if @resource related token was + # cleared by sign out in the meantime + return if @resource.reload.tokens[@client_id].nil? - auth_header = {} + auth_header = @resource.build_auth_header(@token, @client_id) - if not DeviseTokenAuth.change_headers_on_each_request - auth_header = @resource.build_auth_header(@token, @client_id) + # update the response header + response.headers.merge!(auth_header) - # update the response header - response.headers.merge!(auth_header) + else - # extend expiration of batch buffer to account for the duration of - # this request - elsif @is_batch_request - auth_header = @resource.extend_batch_buffer(@token, @client_id) + # Lock the user record during any auth_header updates to ensure + # we don't have write contention from multiple threads + @resource.with_lock do + # should not append auth header if @resource related token was + # cleared by sign out in the meantime + return if @used_auth_by_token && @resource.tokens[@client_id].nil? - # update Authorization response header with new token - else - auth_header = @resource.create_new_auth_token(@client_id) + # determine batch request status after request processing, in case + # another processes has updated it during that processing + @is_batch_request = is_batch_request?(@resource, @client_id) - # update the response header - response.headers.merge!(auth_header) - end + auth_header = {} - end # end lock + # extend expiration of batch buffer to account for the duration of + # this request + if @is_batch_request + auth_header = @resource.extend_batch_buffer(@token, @client_id) + + # update Authorization response header with new token + else + auth_header = @resource.create_new_auth_token(@client_id) + + # update the response header + response.headers.merge!(auth_header) + end + + end # end lock + + end end @@ -100,8 +175,9 @@ def resource_class(m=nil) def is_batch_request?(user, client_id) - user.tokens[client_id] and - user.tokens[client_id]['updated_at'] and + !params[:unbatch] && + user.tokens[client_id] && + user.tokens[client_id]['updated_at'] && Time.parse(user.tokens[client_id]['updated_at']) > @request_started_at - DeviseTokenAuth.batch_request_buffer_throttle end end diff --git a/app/controllers/devise_token_auth/confirmations_controller.rb b/app/controllers/devise_token_auth/confirmations_controller.rb index ed9bf1720..16f85ac78 100644 --- a/app/controllers/devise_token_auth/confirmations_controller.rb +++ b/app/controllers/devise_token_auth/confirmations_controller.rb @@ -3,7 +3,7 @@ class ConfirmationsController < DeviseTokenAuth::ApplicationController def show @resource = resource_class.confirm_by_token(params[:confirmation_token]) - if @resource and @resource.id + if @resource && @resource.id # create client id client_id = SecureRandom.urlsafe_base64(nil, false) token = SecureRandom.urlsafe_base64(nil, false) @@ -17,6 +17,8 @@ def show @resource.save! + yield @resource if block_given? + redirect_to(@resource.build_auth_url(params[:redirect_url], { token: token, client_id: client_id, diff --git a/app/controllers/devise_token_auth/omniauth_callbacks_controller.rb b/app/controllers/devise_token_auth/omniauth_callbacks_controller.rb index 6ecf9b853..ea06b59dc 100644 --- a/app/controllers/devise_token_auth/omniauth_callbacks_controller.rb +++ b/app/controllers/devise_token_auth/omniauth_callbacks_controller.rb @@ -1,75 +1,81 @@ module DeviseTokenAuth class OmniauthCallbacksController < DeviseTokenAuth::ApplicationController - skip_before_filter :set_user_by_token - skip_after_filter :update_auth_header + + attr_reader :auth_params + skip_before_action :set_user_by_token, raise: false + skip_after_action :update_auth_header # intermediary route for successful omniauth authentication. omniauth does # not support multiple models, so we must resort to this terrible hack. def redirect_callbacks + # derive target redirect route from 'resource_class' param, which was set # before authentication. - devise_mapping = request.env['omniauth.params']['resource_class'].underscore.to_sym - redirect_route = "#{Devise.mappings[devise_mapping].as_json["path_prefix"]}/#{params[:provider]}/callback" - - # preserve omniauth info for success route - session['dta.omniauth.auth'] = request.env['omniauth.auth'] + devise_mapping = [request.env['omniauth.params']['namespace_name'], + request.env['omniauth.params']['resource_class'].underscore.gsub('/', '_')].compact.join('_') + path = "#{Devise.mappings[devise_mapping.to_sym].fullpath}/#{params[:provider]}/callback" + klass = request.scheme == 'https' ? URI::HTTPS : URI::HTTP + redirect_route = klass.build(host: request.host, port: request.port, path: path).to_s + + # preserve omniauth info for success route. ignore 'extra' in twitter + # auth response to avoid CookieOverflow. + session['dta.omniauth.auth'] = request.env['omniauth.auth'].except('extra') session['dta.omniauth.params'] = request.env['omniauth.params'] redirect_to redirect_route end def omniauth_success - # find or create user by provider and provider uid - @resource = resource_class.where({ - uid: auth_hash['uid'], - provider: auth_hash['provider'] - }).first_or_initialize - - # create token info - @client_id = SecureRandom.urlsafe_base64(nil, false) - @token = SecureRandom.urlsafe_base64(nil, false) - @expiry = (Time.now + DeviseTokenAuth.token_lifespan).to_i - - @auth_origin_url = generate_url(omniauth_params['auth_origin_url'], { - token: @token, - client_id: @client_id, - uid: @resource.uid, - expiry: @expiry - }) - - # set crazy password for new oauth users. this is only used to prevent - # access via email sign-in. - unless @resource.id - p = SecureRandom.urlsafe_base64(nil, false) - @resource.password = p - @resource.password_confirmation = p + get_resource_from_auth_hash + create_token_info + set_token_on_resource + create_auth_params + + if resource_class.devise_modules.include?(:confirmable) + # don't send confirmation email!!! + @resource.skip_confirmation! end - @resource.tokens[@client_id] = { - token: BCrypt::Password.create(@token), - expiry: @expiry - } + sign_in(:user, @resource, store: false, bypass: false) - # sync user info with provider, update/generate auth token - assign_provider_attrs(@resource, auth_hash) + @resource.save! - # assign any additional (whitelisted) attributes - extra_params = whitelisted_params - @resource.assign_attributes(extra_params) if extra_params + yield @resource if block_given? - # don't send confirmation email!!! - @resource.skip_confirmation! + render_data_or_redirect('deliverCredentials', @auth_params.as_json, @resource.as_json) + end - sign_in(:user, @resource, store: false, bypass: false) + def omniauth_failure + @error = params[:message] + render_data_or_redirect('authFailure', {error: @error}) + end - @resource.save! + protected - # render user info to javascript postMessage communication window - respond_to do |format| - format.html { render :layout => "omniauth_response", :template => "devise_token_auth/omniauth_success" } + # this will be determined differently depending on the action that calls + # it. redirect_callbacks is called upon returning from successful omniauth + # authentication, and the target params live in an omniauth-specific + # request.env variable. this variable is then persisted thru the redirect + # using our own dta.omniauth.params session var. the omniauth_success + # method will access that session var and then destroy it immediately + # after use. In the failure case, finally, the omniauth params + # are added as query params in our monkey patch to OmniAuth in engine.rb + def omniauth_params + if !defined?(@_omniauth_params) + if request.env['omniauth.params'] && request.env['omniauth.params'].any? + @_omniauth_params = request.env['omniauth.params'] + elsif session['dta.omniauth.params'] && session['dta.omniauth.params'].any? + @_omniauth_params ||= session.delete('dta.omniauth.params') + @_omniauth_params + elsif params['omniauth_window_type'] + @_omniauth_params = params.slice('omniauth_window_type', 'auth_origin_url', 'resource_class', 'origin') + else + @_omniauth_params = {} + end end - end + @_omniauth_params + end # break out provider attribute assignment for easy method extension def assign_provider_attrs(user, auth_hash) @@ -81,19 +87,9 @@ def assign_provider_attrs(user, auth_hash) }) end - - def omniauth_failure - @error = params[:message] - - respond_to do |format| - format.html { render :layout => "omniauth_response", :template => "devise_token_auth/omniauth_failure" } - end - end - - # derive allowed params from the standard devise parameter sanitizer def whitelisted_params - whitelist = devise_parameter_sanitizer.for(:sign_up) + whitelist = params_for_resource(:sign_up) whitelist.inject({}){|coll, key| param = omniauth_params[key.to_s] @@ -104,10 +100,13 @@ def whitelisted_params } end - # pull resource class from omniauth return - def resource_class - if omniauth_params + def resource_class(mapping = nil) + if omniauth_params['resource_class'] omniauth_params['resource_class'].constantize + elsif params['resource_class'] + params['resource_class'].constantize + else + raise "No resource_class found" end end @@ -115,20 +114,18 @@ def resource_name resource_class end - # this will be determined differently depending on the action that calls - # it. redirect_callbacks is called upon returning from successful omniauth - # authentication, and the target params live in an omniauth-specific - # request.env variable. this variable is then persisted thru the redirect - # using our own dta.omniauth.params session var. the omniauth_success - # method will access that session var and then destroy it immediately - # after use. - def omniauth_params - if request.env['omniauth.params'] - request.env['omniauth.params'] - else - @_omniauth_params ||= session.delete('dta.omniauth.params') - @_omniauth_params - end + def omniauth_window_type + omniauth_params['omniauth_window_type'] + end + + def auth_origin_url + omniauth_params['auth_origin_url'] || omniauth_params['origin'] + end + + # in the success case, omniauth_window_type is in the omniauth_params. + # in the failure case, it is in a query param. See monkey patch above + def omniauth_window_type + omniauth_params.nil? ? params['omniauth_window_type'] : omniauth_params['omniauth_window_type'] end # this sesison value is set by the redirect_callbacks method. its purpose @@ -148,24 +145,114 @@ def assert_is_devise_resource! # necessary for access to devise_parameter_sanitizers def devise_mapping if omniauth_params - Devise.mappings[omniauth_params['resource_class'].underscore.to_sym] + Devise.mappings[[omniauth_params['namespace_name'], + omniauth_params['resource_class'].underscore].compact.join('_').to_sym] else request.env['devise.mapping'] end end - def generate_url(url, params = {}) - auth_url = url + def set_random_password + # set crazy password for new oauth users. this is only used to prevent + # access via email sign-in. + p = SecureRandom.urlsafe_base64(nil, false) + @resource.password = p + @resource.password_confirmation = p + end + + def create_token_info + # create token info + @client_id = SecureRandom.urlsafe_base64(nil, false) + @token = SecureRandom.urlsafe_base64(nil, false) + @expiry = (Time.now + DeviseTokenAuth.token_lifespan).to_i + @config = omniauth_params['config_name'] + end + + def create_auth_params + @auth_params = { + auth_token: @token, + client_id: @client_id, + uid: @resource.uid, + expiry: @expiry, + config: @config + } + @auth_params.merge!(oauth_registration: true) if @oauth_registration + @auth_params + end + + def set_token_on_resource + @resource.tokens[@client_id] = { + token: BCrypt::Password.create(@token), + expiry: @expiry + } + end + + def render_data(message, data) + @data = data.merge({ + message: message + }) + render :layout => nil, :template => "devise_token_auth/omniauth_external_window" + end + + def render_data_or_redirect(message, data, user_data = {}) + + # We handle inAppBrowser and newWindow the same, but it is nice + # to support values in case people need custom implementations for each case + # (For example, nbrustein does not allow new users to be created if logging in with + # an inAppBrowser) + # + # See app/views/devise_token_auth/omniauth_external_window.html.erb to understand + # why we can handle these both the same. The view is setup to handle both cases + # at the same time. + if ['inAppBrowser', 'newWindow'].include?(omniauth_window_type) + render_data(message, user_data.merge(data)) + + elsif auth_origin_url # default to same-window implementation, which forwards back to auth_origin_url + + # build and redirect to destination url + redirect_to DeviseTokenAuth::Url.generate(auth_origin_url, data.merge(blank: true)) + else + + # there SHOULD always be an auth_origin_url, but if someone does something silly + # like coming straight to this url or refreshing the page at the wrong time, there may not be one. + # In that case, just render in plain text the error message if there is one or otherwise + # a generic message. + fallback_render data[:error] || 'An error occurred' + end + end + + def fallback_render(text) + render inline: %Q| - # ensure that hash-bang is present BEFORE querystring for angularjs - unless url.match(/#/) - auth_url += '#' + + + + #{text} + + | + end + + def get_resource_from_auth_hash + # find or create user by provider and provider uid + @resource = resource_class.where({ + uid: auth_hash['uid'], + provider: auth_hash['provider'] + }).first_or_initialize + + if @resource.new_record? + @oauth_registration = true + set_random_password end - # add query AFTER hash-bang - auth_url += "?#{params.to_query}" + # sync user info with provider, update/generate auth token + assign_provider_attrs(@resource, auth_hash) - return auth_url + # assign any additional (whitelisted) attributes + extra_params = whitelisted_params + @resource.assign_attributes(extra_params) if extra_params + + @resource end + end end diff --git a/app/controllers/devise_token_auth/passwords_controller.rb b/app/controllers/devise_token_auth/passwords_controller.rb index e90cc556f..58022c789 100644 --- a/app/controllers/devise_token_auth/passwords_controller.rb +++ b/app/controllers/devise_token_auth/passwords_controller.rb @@ -1,80 +1,81 @@ module DeviseTokenAuth class PasswordsController < DeviseTokenAuth::ApplicationController - before_filter :set_user_by_token, :only => [:update] - skip_after_filter :update_auth_header, :only => [:create, :edit] + before_action :set_user_by_token, :only => [:update] + skip_after_action :update_auth_header, :only => [:create, :edit] # this action is responsible for generating password reset tokens and # sending emails def create unless resource_params[:email] - return render json: { - success: false, - errors: ['You must provide an email address.'] - }, status: 401 + return render_create_error_missing_email end - unless params[:redirect_url] - return render json: { - success: false, - errors: ['Missing redirect url.'] - }, status: 401 + # give redirect value from params priority + @redirect_url = params[:redirect_url] + + # fall back to default value if provided + @redirect_url ||= DeviseTokenAuth.default_password_reset_url + + unless @redirect_url + return render_create_error_missing_redirect_url + end + + # if whitelist is set, validate redirect_url against whitelist + if DeviseTokenAuth.redirect_whitelist + unless DeviseTokenAuth::Url.whitelisted?(@redirect_url) + return render_create_error_not_allowed_redirect_url + end end # honor devise configuration for case_insensitive_keys if resource_class.case_insensitive_keys.include?(:email) - email = resource_params[:email].downcase + @email = resource_params[:email].downcase else - email = resource_params[:email] + @email = resource_params[:email] end - q = "uid='#{email}' AND provider='email'" + q = "uid = ? AND provider='email'" # fix for mysql default case insensitivity if ActiveRecord::Base.connection.adapter_name.downcase.starts_with? 'mysql' - q = "BINARY uid='#{email}' AND provider='email'" + q = "BINARY uid = ? AND provider='email'" end - @resource = resource_class.where(q).first - - errors = nil + @resource = resource_class.where(q, @email).first + @errors = nil + @error_status = 400 if @resource + yield @resource if block_given? @resource.send_reset_password_instructions({ - email: email, + email: @email, provider: 'email', - redirect_url: params[:redirect_url], + redirect_url: @redirect_url, client_config: params[:config_name] }) if @resource.errors.empty? - render json: { - success: true, - message: "An email has been sent to #{email} containing "+ - "instructions for resetting your password." - } + return render_create_success else - errors = @resource.errors + @errors = @resource.errors end else - errors = ["Unable to find user with email '#{email}'."] + @errors = [I18n.t("devise_token_auth.passwords.user_not_found", email: @email)] + @error_status = 404 end - if errors - render json: { - success: false, - errors: errors - }, status: 400 + if @errors + return render_create_error end end - - # this is where users arrive after visiting the email confirmation link + # this is where users arrive after visiting the password reset confirmation link def edit @resource = resource_class.reset_password_by_token({ reset_password_token: resource_params[:reset_password_token] }) - if @resource and @resource.id + if @resource && @resource.id client_id = SecureRandom.urlsafe_base64(nil, false) token = SecureRandom.urlsafe_base64(nil, false) token_hash = BCrypt::Password.create(token) @@ -86,9 +87,13 @@ def edit } # ensure that user is confirmed - @resource.skip_confirmation! unless @resource.confirmed_at + @resource.skip_confirmation! if @resource.devise_modules.include?(:confirmable) && !@resource.confirmed_at + + # allow user to change password once without current_password + @resource.allow_password_change = true; @resource.save! + yield @resource if block_given? redirect_to(@resource.build_auth_url(params[:redirect_url], { token: token, @@ -97,36 +102,49 @@ def edit config: params[:config] })) else - raise ActionController::RoutingError.new('Not Found') + render_edit_error end end + def update # make sure user is authorized + #return render json: @resource.encrypted_password + unless @resource - return render json: { - success: false, - errors: ['Unauthorized'] - }, status: 401 + return render_update_error_unauthorized end # make sure account doesn't use oauth2 provider unless @resource.provider == 'email' - return render json: { - success: false, - errors: ["This account does not require a password. Sign in using "+ - "your #{@resource.provider.humanize} account instead."] - }, status: 422 + return render_update_error_password_not_required end + # ensure that password params were sent - unless password_resource_params[:password] and password_resource_params[:password_confirmation] + unless password_resource_params[:password] && password_resource_params[:password_confirmation] + return render_update_error_missing_password + end + + # Verify password & confirmation_password are the same + unless password_resource_params[:password] == password_resource_params[:password_confirmation] return render json: { success: false, - errors: ['You must fill out the fields labeled "password" and "password confirmation".'] + errors: ['Doesn\'t match the password and password confirmation.'] }, status: 422 end + #verify current password + unless password_resource_params[:current_password].blank? + unless @resource.valid_password?(password_resource_params[:current_password]) + return render json: { + success: false, + errors: "Your current password is incorrect." + }, status: 499 + end + params.delete :current_password + end + if @resource.update_attributes(password_resource_params) return render json: { success: true, @@ -136,20 +154,105 @@ def update } } else - return render json: { - success: false, - errors: @resource.errors - }, status: 422 + return render_update_error end end - def password_resource_params - params.permit(devise_parameter_sanitizer.for(:account_update)) + protected + + def resource_update_method + if DeviseTokenAuth.check_current_password_before_update == false or @resource.allow_password_change == true + "update_attributes" + else + "update_with_password" + end + end + + def render_create_error_missing_email + render json: { + success: false, + errors: [I18n.t("devise_token_auth.passwords.missing_email")] + }, status: 401 + end + + def render_create_error_missing_redirect_url + render json: { + success: false, + errors: [I18n.t("devise_token_auth.passwords.missing_redirect_url")] + }, status: 401 end + def render_create_error_not_allowed_redirect_url + render json: { + status: 'error', + data: resource_data, + errors: [I18n.t("devise_token_auth.passwords.not_allowed_redirect_url", redirect_url: @redirect_url)] + }, status: 422 + end + + def render_create_success + render json: { + success: true, + message: I18n.t("devise_token_auth.passwords.sended", email: @email) + } + end + + def render_create_error + render json: { + success: false, + errors: @errors, + }, status: @error_status + end + + def render_edit_error + raise ActionController::RoutingError.new('Not Found') + end + + def render_update_error_unauthorized + render json: { + success: false, + errors: ['Unauthorized'] + }, status: 401 + end + + def render_update_error_password_not_required + render json: { + success: false, + errors: [I18n.t("devise_token_auth.passwords.password_not_required", provider: @resource.provider.humanize)] + }, status: 422 + end + + def render_update_error_missing_password + render json: { + success: false, + errors: [I18n.t("devise_token_auth.passwords.missing_passwords")] + }, status: 422 + end + + def render_update_success + render json: { + success: true, + data: resource_data, + message: I18n.t("devise_token_auth.passwords.successfully_updated") + } + end + + def render_update_error + return render json: { + success: false, + errors: resource_errors + }, status: 422 + end + + private + def resource_params - params.permit(:email, :password, :password_confirmation, :reset_password_token) + params.permit(:email,:current_password, :password, :password_confirmation, :reset_password_token, :redirect_url, :config) end + def password_resource_params + params.permit(*params_for_resource(:account_update)) + end + end end diff --git a/app/controllers/devise_token_auth/registrations_controller.rb b/app/controllers/devise_token_auth/registrations_controller.rb index fb776d401..79cdd5c9f 100644 --- a/app/controllers/devise_token_auth/registrations_controller.rb +++ b/app/controllers/devise_token_auth/registrations_controller.rb @@ -1,34 +1,51 @@ module DeviseTokenAuth class RegistrationsController < DeviseTokenAuth::ApplicationController - before_filter :set_user_by_token, :only => [:destroy, :update] - skip_after_filter :update_auth_header, :only => [:create, :destroy] - - respond_to :json + before_action :set_user_by_token, :only => [:destroy, :update] + before_action :validate_sign_up_params, :only => :create + before_action :validate_account_update_params, :only => :update + skip_after_action :update_auth_header, :only => [:create, :destroy] def create @resource = resource_class.new(sign_up_params) - @resource.uid = sign_up_params[:email] @resource.provider = "email" + # honor devise configuration for case_insensitive_keys + if resource_class.case_insensitive_keys.include?(:email) + @resource.email = sign_up_params[:email].try :downcase + else + @resource.email = sign_up_params[:email] + end + + # give redirect value from params priority + @redirect_url = params[:confirm_success_url] + + # fall back to default value if provided + @redirect_url ||= DeviseTokenAuth.default_confirm_success_url + # success redirect url is required - unless params[:confirm_success_url] - return render json: { - status: 'error', - data: @resource, - errors: ["Missing `confirm_success_url` param."] - }, status: 403 + if resource_class.devise_modules.include?(:confirmable) && !@redirect_url + return render_create_error_missing_confirm_success_url + end + + # if whitelist is set, validate redirect_url against whitelist + if DeviseTokenAuth.redirect_whitelist + unless DeviseTokenAuth::Url.whitelisted?(@redirect_url) + return render_create_error_redirect_url_not_allowed + end end begin # override email confirmation, must be sent manually from ctrl + resource_class.set_callback("create", :after, :send_on_create_confirmation_instructions) resource_class.skip_callback("create", :after, :send_on_create_confirmation_instructions) if @resource.save + yield @resource if block_given? unless @resource.confirmed? # user will require email authentication @resource.send_confirmation_instructions({ client_config: params[:config_name], - redirect_url: params[:confirm_success_url] + redirect_url: @redirect_url }) else @@ -45,72 +62,152 @@ def create update_auth_header end - - render json: { - status: 'success', - data: @resource.as_json - } + render_create_success else clean_up_passwords @resource - render json: { - status: 'error', - data: @resource, - errors: @resource.errors.to_hash.merge(full_messages: @resource.errors.full_messages) - }, status: 403 + render_create_error end rescue ActiveRecord::RecordNotUnique clean_up_passwords @resource - render json: { - status: 'error', - data: @resource, - errors: ["An account already exists for #{@resource.email}"] - }, status: 403 + render_create_error_email_already_exists end end def update if @resource - if @resource.update_attributes(account_update_params) - render json: { - status: 'success', - data: @resource.as_json - } + if @resource.send(resource_update_method, account_update_params) + yield @resource if block_given? + render_update_success else - render json: { - status: 'error', - errors: @resource.errors - }, status: 403 + render_update_error end else - render json: { - status: 'error', - errors: ["User not found."] - }, status: 404 + render_update_error_user_not_found end end def destroy if @resource @resource.destroy + yield @resource if block_given? - render json: { - status: 'success', - message: "Account with uid #{@resource.uid} has been destroyed." - } + render_destroy_success else - render json: { - status: 'error', - errors: ["Unable to locate account for destruction."] - }, status: 404 + render_destroy_error end end def sign_up_params - params.permit(devise_parameter_sanitizer.for(:sign_up)) + params.permit(*params_for_resource(:sign_up)) end def account_update_params - params.permit(devise_parameter_sanitizer.for(:account_update)) + params.permit(*params_for_resource(:account_update)) + end + + protected + + def render_create_error_missing_confirm_success_url + render json: { + status: 'error', + data: resource_data, + errors: [I18n.t("devise_token_auth.registrations.missing_confirm_success_url")] + }, status: 422 + end + + def render_create_error_redirect_url_not_allowed + render json: { + status: 'error', + data: resource_data, + errors: [I18n.t("devise_token_auth.registrations.redirect_url_not_allowed", redirect_url: @redirect_url)] + }, status: 422 + end + + def render_create_success + render json: { + status: 'success', + data: resource_data + } + end + + def render_create_error + render json: { + status: 'error', + data: resource_data, + errors: resource_errors + }, status: 422 + end + + def render_create_error_email_already_exists + render json: { + status: 'error', + data: resource_data, + errors: [I18n.t("devise_token_auth.registrations.email_already_exists", email: @resource.email)] + }, status: 422 + end + + def render_update_success + render json: { + status: 'success', + data: resource_data + } + end + + def render_update_error + render json: { + status: 'error', + errors: resource_errors + }, status: 422 + end + + def render_update_error_user_not_found + render json: { + status: 'error', + errors: [I18n.t("devise_token_auth.registrations.user_not_found")] + }, status: 404 + end + + def render_destroy_success + render json: { + status: 'success', + message: I18n.t("devise_token_auth.registrations.account_with_uid_destroyed", uid: @resource.uid) + } + end + + def render_destroy_error + render json: { + status: 'error', + errors: [I18n.t("devise_token_auth.registrations.account_to_destroy_not_found")] + }, status: 404 + end + + private + + def resource_update_method + if DeviseTokenAuth.check_current_password_before_update == :attributes + "update_with_password" + elsif DeviseTokenAuth.check_current_password_before_update == :password && account_update_params.has_key?(:password) + "update_with_password" + elsif account_update_params.has_key?(:current_password) + "update_with_password" + else + "update_attributes" + end + end + + def validate_sign_up_params + validate_post_data sign_up_params, I18n.t("errors.messages.validate_sign_up_params") + end + + def validate_account_update_params + validate_post_data account_update_params, I18n.t("errors.messages.validate_account_update_params") + end + + def validate_post_data which, message + render json: { + status: 'error', + errors: [message] + }, status: :unprocessable_entity if which.empty? end end end diff --git a/app/controllers/devise_token_auth/sessions_controller.rb b/app/controllers/devise_token_auth/sessions_controller.rb index 447b8d37b..88984807f 100644 --- a/app/controllers/devise_token_auth/sessions_controller.rb +++ b/app/controllers/devise_token_auth/sessions_controller.rb @@ -1,7 +1,12 @@ # see http://www.emilsoman.com/blog/2013/05/18/building-a-tested/ module DeviseTokenAuth class SessionsController < DeviseTokenAuth::ApplicationController - before_filter :set_user_by_token, :only => [:destroy] + before_action :set_user_by_token, :only => [:destroy] + after_action :reset_session, :only => [:destroy] + + def new + render_new_error + end def create # honor devise configuration for case_insensitive_keys @@ -10,33 +15,68 @@ def create else email = resource_params[:email] end - - q = "uid='#{email}' AND provider='email'" + provider=resource_params[:provider] + q = provider == "email" ? "uid='#{email}' AND provider='#{provider}'" : "uid='#{provider}@#{email}' AND provider='#{provider}'" if ActiveRecord::Base.connection.adapter_name.downcase.starts_with? 'mysql' - q = "BINARY uid='#{email}' AND provider='email'" + q = provider == "email" ? "BINARY uid='#{email}' AND provider='#{provider}'" : "BINARY uid='#{provider}@#{email}' AND provider='#{provider}'" end - + @resource = resource_class.where(q).first - + if @resource and valid_params? and @resource.valid_password?(resource_params[:password]) and @resource.confirmed? # create client id @client_id = SecureRandom.urlsafe_base64(nil, false) @token = SecureRandom.urlsafe_base64(nil, false) - + @external_token = SecureRandom.urlsafe_base64(nil, false) + @resource.tokens[@client_id] = { token: BCrypt::Password.create(@token), + external_token: BCrypt::Password.create(@external_token), expiry: (Time.now + DeviseTokenAuth.token_lifespan).to_i } @resource.save sign_in(:user, @resource, store: false, bypass: false) - - render json: { - data: @resource.as_json(except: [ - :tokens, :created_at, :updated_at - ]) - } + if @resource.class.to_s == 'Agent' + LoginBitacoraAgent.create( + :agency_id => @resource.agency_id, + :profile_id => @resource.profile_id, + :agent_id =>@resource.id, + :email =>@resource.email, + :is_owner =>@resource.is_owner, + :sign_in_ip =>@resource.current_sign_in_ip, + :action_type =>LoginBitacoraAgent.action_types[:sign_in] + ) + render json: { + data: @resource.as_json(only: [ + :id, + :email, + :provider, + :uid, + :agency_id, + :name, + :last_name, + :is_owner, + :avatar_file_name, + :avatar_content_type, + :telephone, + :admin_license, + :sign_in_count],include: {agency: { + except:[:sabre_ipcc,:sabre_password,:sabre_username]}, + profile:{ + include: { functionalities:{} + } + } + }).merge("external_token" => {client:@client_id, token: @external_token }) + } + else + render json: { + data: @resource.as_json(except: [ + :tokens, :created_at, :updated_at + ]) + } + end elsif @resource and not @resource.confirmed? render json: { @@ -47,41 +87,117 @@ def create "can be activated" ] }, status: 401 - + render_create_success + elsif @resource && !(!@resource.respond_to?(:active_for_authentication?) || @resource.active_for_authentication?) + render_create_error_not_confirmed else - render json: { - errors: ["Invalid login credentials. Please try again."] - }, status: 401 + render_create_error_bad_credentials end end def destroy - # remove auth instance variables so that after_filter does not run + # remove auth instance variables so that after_action does not run user = remove_instance_variable(:@resource) if @resource client_id = remove_instance_variable(:@client_id) if @client_id remove_instance_variable(:@token) if @token if user and client_id and user.tokens[client_id] + + if user.class.to_s == 'Agent' + LoginBitacoraAgent.create( + :agency_id => user.agency_id, + :profile_id => user.profile_id, + :agent_id =>user.id, + :email =>user.email, + :is_owner =>user.is_owner, + :sign_in_ip =>user.current_sign_in_ip, + :action_type =>LoginBitacoraAgent.action_types[:sign_out] + ) + end user.tokens.delete(client_id) user.save! - render json: { - success:true - }, status: 200 + yield user if block_given? + render_destroy_success else - render json: { - errors: ["User was not found or was not logged in."] - }, status: 404 + render_destroy_error end end + protected + def valid_params? resource_params[:password] && resource_params[:email] end + def get_auth_params + auth_key = nil + auth_val = nil + + # iterate thru allowed auth keys, use first found + resource_class.authentication_keys.each do |k| + if resource_params[k] + auth_val = resource_params[k] + auth_key = k + break + end + end + + # honor devise configuration for case_insensitive_keys + if resource_class.case_insensitive_keys.include?(auth_key) + auth_val.downcase! + end + + return { + key: auth_key, + val: auth_val + } + end + + def render_new_error + render json: { + errors: [ I18n.t("devise_token_auth.sessions.not_supported")] + }, status: 405 + end + + def render_create_success + render json: { + data: resource_data(resource_json: @resource.token_validation_response) + } + end + + def render_create_error_not_confirmed + render json: { + success: false, + errors: [ I18n.t("devise_token_auth.sessions.not_confirmed", email: @resource.email) ] + }, status: 401 + end + + def render_create_error_bad_credentials + render json: { + errors: [I18n.t("devise_token_auth.sessions.bad_credentials")] + }, status: 401 + end + + def render_destroy_success + render json: { + success:true + }, status: 200 + end + + def render_destroy_error + render json: { + errors: [I18n.t("devise_token_auth.sessions.user_not_found")] + }, status: 404 + end + + + private + def resource_params - params.permit(devise_parameter_sanitizer.for(:sign_in)) + params.permit(*params_for_resource(:sign_in)) end + end end diff --git a/app/controllers/devise_token_auth/token_validations_controller.rb b/app/controllers/devise_token_auth/token_validations_controller.rb index 52da3d9b9..11edcf1e6 100644 --- a/app/controllers/devise_token_auth/token_validations_controller.rb +++ b/app/controllers/devise_token_auth/token_validations_controller.rb @@ -1,9 +1,20 @@ module DeviseTokenAuth class TokenValidationsController < DeviseTokenAuth::ApplicationController - skip_before_filter :assert_is_devise_resource!, :only => [:validate_token] - before_filter :set_user_by_token, :only => [:validate_token] + skip_before_action :assert_is_devise_resource!, :only => [:validate_token,:validate_external_token] + before_action :set_user_by_token, :only => [:validate_token] + before_action :set_user_by_external_token, :only => [:validate_external_token] def validate_token + # @resource will have been set by set_user_token concern + if @resource + yield @resource if block_given? + render_validate_token_success + else + render_validate_token_error + end + end + + def validate_external_token # @resource will have been set by set_user_token concern if @resource render json: { @@ -19,5 +30,21 @@ def validate_token }, status: 401 end end + + protected + + def render_validate_token_success + render json: { + success: true, + data: resource_data(resource_json: @resource.token_validation_response) + } + end + + def render_validate_token_error + render json: { + success: false, + errors: [I18n.t("devise_token_auth.token_validations.invalid")] + }, status: 401 + end end end diff --git a/app/models/devise_token_auth/concerns/user.rb b/app/models/devise_token_auth/concerns/user.rb index 0ef89c7d0..29faabbf1 100644 --- a/app/models/devise_token_auth/concerns/user.rb +++ b/app/models/devise_token_auth/concerns/user.rb @@ -1,20 +1,35 @@ +require 'bcrypt' + module DeviseTokenAuth::Concerns::User extend ActiveSupport::Concern - included do - # Include default devise modules. Others available are: - # :confirmable, :lockable, :timeoutable and :omniauthable - devise :database_authenticatable, :registerable, - :recoverable, :rememberable, :trackable, :validatable, - :confirmable, :omniauthable + def self.tokens_match?(token_hash, token) + @token_equality_cache ||= {} + + key = "#{token_hash}/#{token}" + result = @token_equality_cache[key] ||= (::BCrypt::Password.new(token_hash) == token) + if @token_equality_cache.size > 10000 + @token_equality_cache = {} + end + result + end - serialize :tokens, JSON + included do + # Hack to check if devise is already enabled + unless self.method_defined?(:devise_modules) + devise :database_authenticatable, :registerable, + :recoverable, :trackable, :validatable, :confirmable + else + self.devise_modules.delete(:omniauthable) + end - validates_presence_of :email, if: Proc.new { |u| u.provider == 'email' } - validates_presence_of :uid + unless tokens_has_json_column_type? + serialize :tokens, JSON + end - # only validate unique emails among email registration users - validate :unique_email_user, on: :create + if DeviseTokenAuth.default_callbacks + include DeviseTokenAuth::Concerns::UserOmniauthCallbacks + end # can't set default on text fields in mysql, simulate here instead. after_save :set_empty_token_hash @@ -23,6 +38,14 @@ module DeviseTokenAuth::Concerns::User # get rid of dead tokens before_save :destroy_expired_tokens + # remove old tokens if password has changed + before_save :remove_tokens_after_password_reset + + # allows user to change password without current_password + attr_writer :allow_password_change + def allow_password_change + @allow_password_change || false + end # don't use default devise email validation def email_required? @@ -33,7 +56,6 @@ def email_changed? false end - # override devise method to include additional info as opts hash def send_confirmation_instructions(opts=nil) unless @raw_confirmation_token @@ -48,6 +70,7 @@ def send_confirmation_instructions(opts=nil) if pending_reconfirmation? opts[:to] = unconfirmed_email end + opts[:redirect_url] ||= DeviseTokenAuth.default_confirm_success_url send_devise_notification(:confirmation_instructions, @raw_confirmation_token, opts) end @@ -61,24 +84,34 @@ def send_reset_password_instructions(opts=nil) # fall back to "default" config name opts[:client_config] ||= "default" - if pending_reconfirmation? - opts[:to] = unconfirmed_email - else - opts[:to] = email - end - send_devise_notification(:reset_password_instructions, token, opts) token end end + module ClassMethods + protected + + + def tokens_has_json_column_type? + database_exists? && table_exists? && self.columns_hash['tokens'] && self.columns_hash['tokens'].type.in?([:json, :jsonb]) + end + + def database_exists? + ActiveRecord::Base.connection + rescue ActiveRecord::NoDatabaseError + false + else + true + end + end + def valid_token?(token, client_id='default') client_id ||= 'default' return false unless self.tokens[client_id] - return true if token_is_current?(token, client_id) return true if token_can_be_reused?(token, client_id) @@ -86,6 +119,16 @@ def valid_token?(token, client_id='default') return false end + def valid_external_token?(token, client_id='default') + client_id ||= 'default' + + return false unless self.tokens[client_id] + return true if externaltoken_is_current?(token, client_id) + + # return false if none of the above conditions are met + return false + end + # this must be done from the controller so that additional params # can be passed on from the client @@ -93,34 +136,56 @@ def send_confirmation_notification? false end - - def token_is_current?(token, client_id) + def externaltoken_is_current?(token, client_id) return true if ( # ensure that expiry and token are set self.tokens[client_id]['expiry'] and - self.tokens[client_id]['token'] and + self.tokens[client_id]['external_token'] and # ensure that the token has not yet expired DateTime.strptime(self.tokens[client_id]['expiry'].to_s, '%s') > Time.now and # ensure that the token is valid - BCrypt::Password.new(self.tokens[client_id]['token']) == token + BCrypt::Password.new(self.tokens[client_id]['external_token']) == token ) end + def token_is_current?(token, client_id) + # ghetto HashWithIndifferentAccess + expiry = self.tokens[client_id]['expiry'] || self.tokens[client_id][:expiry] + token_hash = self.tokens[client_id]['token'] || self.tokens[client_id][:token] + + return true if ( + # ensure that expiry and token are set + expiry && token && + + # ensure that the token has not yet expired + DateTime.strptime(expiry.to_s, '%s') > Time.now && + + # ensure that the token is valid + DeviseTokenAuth::Concerns::User.tokens_match?(token_hash, token) + ) + end + + + # allow batch requests to use the previous token def token_can_be_reused?(token, client_id) + # ghetto HashWithIndifferentAccess + updated_at = self.tokens[client_id]['updated_at'] || self.tokens[client_id][:updated_at] + last_token = self.tokens[client_id]['last_token'] || self.tokens[client_id][:last_token] + + return true if ( # ensure that the last token and its creation time exist - self.tokens[client_id]['updated_at'] and - self.tokens[client_id]['last_token'] and + updated_at && last_token && # ensure that previous token falls within the batch buffer throttle time of the last request - Time.parse(self.tokens[client_id]['updated_at']) > Time.now - DeviseTokenAuth.batch_request_buffer_throttle and + Time.parse(updated_at) > Time.now - DeviseTokenAuth.batch_request_buffer_throttle && # ensure that the token is valid - BCrypt::Password.new(self.tokens[client_id]['last_token']) == token + ::BCrypt::Password.new(last_token) == token ) end @@ -130,10 +195,10 @@ def create_new_auth_token(client_id=nil) client_id ||= SecureRandom.urlsafe_base64(nil, false) last_token ||= nil token = SecureRandom.urlsafe_base64(nil, false) - token_hash = BCrypt::Password.create(token) + token_hash = ::BCrypt::Password.create(token) expiry = (Time.now + DeviseTokenAuth.token_lifespan).to_i - if self.tokens[client_id] and self.tokens[client_id]['token'] + if self.tokens[client_id] && self.tokens[client_id]['token'] last_token = self.tokens[client_id]['token'] end @@ -144,8 +209,6 @@ def create_new_auth_token(client_id=nil) updated_at: Time.now } - self.save! - return build_auth_header(token, client_id) end @@ -155,14 +218,22 @@ def build_auth_header(token, client_id='default') # client may use expiry to prevent validation request if expired # must be cast as string or headers will break - expiry = self.tokens[client_id]['expiry'].to_s + expiry = self.tokens[client_id]['expiry'] || self.tokens[client_id][:expiry] + + max_clients = DeviseTokenAuth.max_number_of_devices + while self.tokens.keys.length > 0 && max_clients < self.tokens.keys.length + oldest_token = self.tokens.min_by { |cid, v| v[:expiry] || v["expiry"] } + self.tokens.delete(oldest_token.first) + end + + self.save! return { - "access-token" => token, - "token-type" => "Bearer", - "client" => client_id, - "expiry" => expiry, - "uid" => self.uid + DeviseTokenAuth.headers_names[:"access-token"] => token, + DeviseTokenAuth.headers_names[:"token-type"] => "Bearer", + DeviseTokenAuth.headers_names[:"client"] => client_id, + DeviseTokenAuth.headers_names[:"expiry"] => expiry.to_s, + DeviseTokenAuth.headers_names[:"uid"] => self.uid } end @@ -171,52 +242,51 @@ def build_auth_url(base_url, args) args[:uid] = self.uid args[:expiry] = self.tokens[args[:client_id]]['expiry'] - generate_url(base_url, args) + DeviseTokenAuth::Url.generate(base_url, args) end def extend_batch_buffer(token, client_id) self.tokens[client_id]['updated_at'] = Time.now - self.save! return build_auth_header(token, client_id) end + def confirmed? + self.devise_modules.exclude?(:confirmable) || super + end - protected - - - # NOTE: ensure that fragment comes AFTER querystring for proper $location - # parsing using AngularJS. - def generate_url(url, params = {}) - uri = URI(url) - - res = "#{uri.scheme}://#{uri.host}" - res += ":#{uri.port}" if (uri.port and uri.port != 80 and uri.port != 443) - res += "#{uri.path}" if uri.path - res += '#' - res += "#{uri.fragment}" if uri.fragment - res += "?#{params.to_query}" - - return res + def token_validation_response + self.as_json(except: [ + :tokens, :created_at, :updated_at + ]) end - # only validate unique email among users that registered by email - def unique_email_user - if provider == 'email' and self.class.where(provider: 'email', email: email).count > 0 - errors.add(:email, "This email address is already in use") - end - end + protected def set_empty_token_hash self.tokens ||= {} if has_attribute?(:tokens) end def destroy_expired_tokens - self.tokens.delete_if{|cid,v| - expiry = v[:expiry] || v["expiry"] - DateTime.strptime(expiry.to_s, '%s') < Time.now - } + if self.tokens + self.tokens.delete_if do |cid, v| + expiry = v[:expiry] || v["expiry"] + DateTime.strptime(expiry.to_s, '%s') < Time.now + end + end end + + def remove_tokens_after_password_reset + there_is_more_than_one_token = self.tokens && self.tokens.keys.length > 1 + should_remove_old_tokens = DeviseTokenAuth.remove_tokens_after_password_reset && + encrypted_password_changed? && there_is_more_than_one_token + + if should_remove_old_tokens + latest_token = self.tokens.max_by { |cid, v| v[:expiry] || v["expiry"] } + self.tokens = { latest_token.first => latest_token.last } + end + end + end diff --git a/app/models/devise_token_auth/concerns/user_omniauth_callbacks.rb b/app/models/devise_token_auth/concerns/user_omniauth_callbacks.rb new file mode 100644 index 000000000..42aa1c849 --- /dev/null +++ b/app/models/devise_token_auth/concerns/user_omniauth_callbacks.rb @@ -0,0 +1,28 @@ +module DeviseTokenAuth::Concerns::UserOmniauthCallbacks + extend ActiveSupport::Concern + + included do + validates :email, presence: true, email: true, if: Proc.new { |u| u.provider == 'email' } + validates_presence_of :uid, if: Proc.new { |u| u.provider != 'email' } + + # only validate unique emails among email registration users + validate :unique_email_user, on: :create + + # keep uid in sync with email + before_save :sync_uid + before_create :sync_uid + end + + protected + + # only validate unique email among users that registered by email + def unique_email_user + if provider == 'email' && self.class.where(provider: 'email', email: email).count > 0 + errors.add(:email, :taken) + end + end + + def sync_uid + self.uid = email if provider == 'email' + end +end diff --git a/app/validators/email_validator.rb b/app/validators/email_validator.rb new file mode 100644 index 000000000..de50350b3 --- /dev/null +++ b/app/validators/email_validator.rb @@ -0,0 +1,21 @@ +class EmailValidator < ActiveModel::EachValidator + def validate_each(record, attribute, value) + unless value =~ /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i + record.errors[attribute] << email_invalid_message + end + end + + private + + def email_invalid_message + # Try strictly set message: + message = options[:message] + + if message.nil? + # Try DeviceTokenAuth translations or fallback to ActiveModel translations + message = I18n.t(:'errors.messages.not_email', default: :'errors.messages.invalid') + end + + message + end +end \ No newline at end of file diff --git a/app/views/devise/mailer/confirmation_instructions.html.erb b/app/views/devise/mailer/confirmation_instructions.html.erb index 13c70d036..dba08dc40 100644 --- a/app/views/devise/mailer/confirmation_instructions.html.erb +++ b/app/views/devise/mailer/confirmation_instructions.html.erb @@ -1,5 +1,5 @@ -

Welcome <%= @email %>!

+

<%= t(:welcome).capitalize + ' ' + @email %>!

-

You can confirm your account email through the link below:

+

<%= t '.confirm_link_msg' %>

-

<%= link_to 'Confirm my account', confirmation_url(@resource, confirmation_token: @token, config: message['client-config'].to_s, redirect_url: message['redirect-url']) %>

+

<%= link_to t('.confirm_account_link'), confirmation_url(@resource, {confirmation_token: @token, config: message['client-config'].to_s, redirect_url: message['redirect-url']}).html_safe %>

diff --git a/app/views/devise/mailer/reset_password_instructions.html.erb b/app/views/devise/mailer/reset_password_instructions.html.erb index 9d6cc6e25..0fc308c40 100644 --- a/app/views/devise/mailer/reset_password_instructions.html.erb +++ b/app/views/devise/mailer/reset_password_instructions.html.erb @@ -1,8 +1,8 @@ -

Hello <%= @resource.email %>!

+

<%= t(:hello).capitalize %> <%= @resource.email %>!

-

Someone has requested a link to change your password. You can do this through the link below.

+

<%= t '.request_reset_link_msg' %>

-

<%= link_to 'Change my password', edit_password_url(@resource, reset_password_token: @token, config: message['client-config'].to_s, redirect_url: message['redirect-url'].to_s) %>

+

<%= link_to t('.password_change_link'), edit_password_url(@resource, reset_password_token: @token, config: message['client-config'].to_s, redirect_url: message['redirect-url'].to_s).html_safe %>

-

If you didn't request this, please ignore this email.

-

Your password won't change until you access the link above and create a new one.

+

<%= t '.ignore_mail_msg' %>

+

<%= t '.no_changes_msg' %>

\ No newline at end of file diff --git a/app/views/devise/mailer/unlock_instructions.html.erb b/app/views/devise/mailer/unlock_instructions.html.erb index 41e148bf2..3beae0f0c 100644 --- a/app/views/devise/mailer/unlock_instructions.html.erb +++ b/app/views/devise/mailer/unlock_instructions.html.erb @@ -1,7 +1,7 @@ -

Hello <%= @resource.email %>!

+

<%= t :hello %> <%= @resource.email %>!

-

Your account has been locked due to an excessive number of unsuccessful sign in attempts.

+

<%= t '.account_lock_msg' %>

-

Click the link below to unlock your account:

+

<%= t '.unlock_link_msg' %>

-

<%= link_to 'Unlock my account', unlock_url(@resource, unlock_token: @token) %>

+

<%= link_to t('.unlock_link'), unlock_url(@resource, unlock_token: @token) %>

diff --git a/app/views/devise_token_auth/omniauth_external_window.html.erb b/app/views/devise_token_auth/omniauth_external_window.html.erb new file mode 100644 index 000000000..0739e4c6d --- /dev/null +++ b/app/views/devise_token_auth/omniauth_external_window.html.erb @@ -0,0 +1,38 @@ + + + + + + +
+    
+ + diff --git a/app/views/devise_token_auth/omniauth_failure.html.erb b/app/views/devise_token_auth/omniauth_failure.html.erb deleted file mode 100644 index e483d3018..000000000 --- a/app/views/devise_token_auth/omniauth_failure.html.erb +++ /dev/null @@ -1,2 +0,0 @@ -message: "authFailure", -error: "<%= @error %>" diff --git a/app/views/devise_token_auth/omniauth_success.html.erb b/app/views/devise_token_auth/omniauth_success.html.erb deleted file mode 100644 index 34ef6b740..000000000 --- a/app/views/devise_token_auth/omniauth_success.html.erb +++ /dev/null @@ -1,8 +0,0 @@ -<% @resource.as_json.each do |attr, val| %> - "<%= attr %>": "<%= val %>", -<% end %> - -"auth_token": "<%= @token %>", -"message": "deliverCredentials", -"client_id": "<%= @client_id %>", -"expiry": "<%= @expiry %>" diff --git a/app/views/layouts/omniauth_response.html.erb b/app/views/layouts/omniauth_response.html.erb deleted file mode 100644 index 2b3d6d3a2..000000000 --- a/app/views/layouts/omniauth_response.html.erb +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - -
-      Redirecting...
-    
- - diff --git a/config/initializers/devise.rb b/config/initializers/devise.rb index 21b85f7ff..58149ce5c 100644 --- a/config/initializers/devise.rb +++ b/config/initializers/devise.rb @@ -142,7 +142,7 @@ # Email regex used to validate email formats. It simply asserts that # one (and only one) @ exists in the given string. This is mainly # to give user feedback and not to assert the e-mail validity. - # config.email_regexp = /\A[^@]+@[^@]+\z/ + config.email_regexp = /\A[^@\s]+@([^@\s]+\.)+[^@\W]+\z/ # ==> Configuration for :timeoutable # The time you want to timeout the user session without activity. After this @@ -193,11 +193,4 @@ # don't serialize tokens Devise::Models::Authenticatable::BLACKLIST_FOR_SERIALIZATION << :tokens - - # mounted routes will point to this - Rails.application.config.after_initialize do - if defined?(::OmniAuth) - ::OmniAuth::config.path_prefix = config.omniauth_path_prefix = DeviseTokenAuth.omniauth_prefix - end - end end diff --git a/config/locales/de.yml b/config/locales/de.yml new file mode 100644 index 000000000..ff03e354f --- /dev/null +++ b/config/locales/de.yml @@ -0,0 +1,49 @@ +de: + devise_token_auth: + sessions: + not_confirmed: "Eine Bestätigungs-E-Mail wurde an Ihre Adresse '%{email}' gesendet. Sie müssen der Anleitung in der E-Mail folgen, um Ihren Account zu aktivieren." + bad_credentials: "Ungültige Anmeldeinformationen. Bitte versuchen Sie es erneut." + not_supported: "Verwenden Sie POST /sign_in zur Anmeldung. GET wird nicht unterstützt." + user_not_found: "Benutzer wurde nicht gefunden oder konnte nicht angemeldet werden." + token_validations: + invalid: "Ungültige Anmeldeinformationen" + registrations: + missing_confirm_success_url: "Fehlender Paramter 'confirm_success_url'." + redirect_url_not_allowed: "Weiterleitung zu '%{redirect_url}' ist nicht gestattet." + email_already_exists: "Es gibt bereits einen Account für '%{email}'." + account_with_uid_destroyed: "Account mit der uid '%{uid}' wurde gelöscht." + account_to_destroy_not_found: "Der zu löschende Account kann nicht gefunden werden." + user_not_found: "Benutzer kann nicht gefunden werden." + passwords: + missing_email: "Sie müssen eine E-Mail-Adresse angeben." + missing_redirect_url: "Es fehlt die URL zu Weiterleitung." + not_allowed_redirect_url: "Weiterleitung zu '%{redirect_url}' ist nicht gestattet." + sended: "Ein E-Mail mit der Anleitung zum Zurücksetzen Ihres Passwortes wurde an '%{email}' gesendet." + user_not_found: "Der Benutzer mit der E-Mail-Adresse '%{email}' kann nicht gefunden werden." + password_not_required: "Dieser Account benötigt kein Passwort. Melden Sie sich stattdessen über Ihren Account bei '%{provider}' an." + missing_passwords: "Sie müssen die Felder 'Passwort' und 'Passwortbestätigung' ausfüllen." + successfully_updated: "Ihr Passwort wurde erfolgreich aktualisiert." + errors: + messages: + validate_sign_up_params: "Bitte übermitteln sie vollständige Anmeldeinformationen im Body des Requests." + validate_account_update_params: "Bitte übermitteln sie vollständige Informationen zur Aktualisierung im Body des Requests." + not_email: "ist keine E-Mail-Adresse" + devise: + mailer: + confirmation_instructions: + subject: "Bestätigung Ihres Kontos" + confirm_link_msg: "Sie können Ihr Konto über den untenstehenden Link bestätigen:" + confirm_account_link: "Konto bestätigen" + reset_password_instructions: + subject: "Passwort zurücksetzen" + request_reset_link_msg: "Jemand hat einen Link zur Änderungen Ihres Passwortes angefordert. Sie können dies durch den folgenden Link tun:" + password_change_link: "Passwort ändern" + ignore_mail_msg: "Wenn Sie keine Änderung Ihres Passwortes angefordert haben, ignorieren Sie bitte diese E-Mail:" + no_changes_msg: "Ihr Passwort wird nicht geändert, bis Sie auf den obigen Link zugreifen und eine neues Passwort erstellen." + unlock_instructions: + subject: "Anweisungen zum Entsperren Ihres Kontos" + account_lock_msg: "Ihr Konto wurde aufgrund einer übermäßigen Anzahl von erfolglosen Anmeldeversuchen gesperrt." + unlock_link_msg: "Klicken Sie auf den Link unten, um Ihr Konto zu entsperren:" + unlock_link: "Entsperren Sie Ihr Konto" + hello: "hallo" + welcome: "willkommen" diff --git a/config/locales/devise.en.yml b/config/locales/devise.en.yml deleted file mode 100644 index abccdb087..000000000 --- a/config/locales/devise.en.yml +++ /dev/null @@ -1,59 +0,0 @@ -# Additional translations at https://github.com/plataformatec/devise/wiki/I18n - -en: - devise: - confirmations: - confirmed: "Your account was successfully confirmed." - send_instructions: "You will receive an email with instructions about how to confirm your account in a few minutes." - send_paranoid_instructions: "If your email address exists in our database, you will receive an email with instructions about how to confirm your account in a few minutes." - failure: - already_authenticated: "You are already signed in." - inactive: "Your account is not activated yet." - invalid: "Invalid email or password." - locked: "Your account is locked." - last_attempt: "You have one more attempt before your account will be locked." - not_found_in_database: "Invalid email or password." - timeout: "Your session expired. Please sign in again to continue." - unauthenticated: "You need to sign in or sign up before continuing." - unconfirmed: "You have to confirm your account before continuing." - mailer: - confirmation_instructions: - subject: "Confirmation instructions" - reset_password_instructions: - subject: "Reset password instructions" - unlock_instructions: - subject: "Unlock Instructions" - omniauth_callbacks: - failure: "Could not authenticate you from %{kind} because \"%{reason}\"." - success: "Successfully authenticated from %{kind} account." - passwords: - no_token: "You can't access this page without coming from a password reset email. If you do come from a password reset email, please make sure you used the full URL provided." - send_instructions: "You will receive an email with instructions on how to reset your password in a few minutes." - send_paranoid_instructions: "If your email address exists in our database, you will receive a password recovery link at your email address in a few minutes." - updated: "Your password was changed successfully. You are now signed in." - updated_not_active: "Your password was changed successfully." - registrations: - destroyed: "Bye! Your account was successfully cancelled. We hope to see you again soon." - signed_up: "Welcome! You have signed up successfully." - signed_up_but_inactive: "You have signed up successfully. However, we could not sign you in because your account is not yet activated." - signed_up_but_locked: "You have signed up successfully. However, we could not sign you in because your account is locked." - signed_up_but_unconfirmed: "A message with a confirmation link has been sent to your email address. Please open the link to activate your account." - update_needs_confirmation: "You updated your account successfully, but we need to verify your new email address. Please check your email and click on the confirm link to finalize confirming your new email address." - updated: "You updated your account successfully." - sessions: - signed_in: "Signed in successfully." - signed_out: "Signed out successfully." - unlocks: - send_instructions: "You will receive an email with instructions about how to unlock your account in a few minutes." - send_paranoid_instructions: "If your account exists, you will receive an email with instructions about how to unlock it in a few minutes." - unlocked: "Your account has been unlocked successfully. Please sign in to continue." - errors: - messages: - already_confirmed: "was already confirmed, please try signing in" - confirmation_period_expired: "needs to be confirmed within %{period}, please request a new one" - expired: "has expired, please request a new one" - not_found: "not found" - not_locked: "was not locked" - not_saved: - one: "1 error prohibited this %{resource} from being saved:" - other: "%{count} errors prohibited this %{resource} from being saved:" diff --git a/config/locales/en.yml b/config/locales/en.yml new file mode 100644 index 000000000..80d6f8ae9 --- /dev/null +++ b/config/locales/en.yml @@ -0,0 +1,46 @@ +en: + devise_token_auth: + sessions: + not_confirmed: "A confirmation email was sent to your account at '%{email}'. You must follow the instructions in the email before your account can be activated" + bad_credentials: "Invalid login credentials. Please try again." + not_supported: "Use POST /sign_in to sign in. GET is not supported." + user_not_found: "User was not found or was not logged in." + token_validations: + invalid: "Invalid login credentials" + registrations: + missing_confirm_success_url: "Missing 'confirm_success_url' parameter." + redirect_url_not_allowed: "Redirect to '%{redirect_url}' not allowed." + email_already_exists: "An account already exists for '%{email}'" + account_with_uid_destroyed: "Account with UID '%{uid}' has been destroyed." + account_to_destroy_not_found: "Unable to locate account for destruction." + user_not_found: "User not found." + passwords: + missing_email: "You must provide an email address." + missing_redirect_url: "Missing redirect URL." + not_allowed_redirect_url: "Redirect to '%{redirect_url}' not allowed." + sended: "An email has been sent to '%{email}' containing instructions for resetting your password." + user_not_found: "Unable to find user with email '%{email}'." + password_not_required: "This account does not require a password. Sign in using your '%{provider}' account instead." + missing_passwords: "You must fill out the fields labeled 'Password' and 'Password confirmation'." + successfully_updated: "Your password has been successfully updated." + errors: + messages: + validate_sign_up_params: "Please submit proper sign up data in request body." + validate_account_update_params: "Please submit proper account update data in request body." + not_email: "is not an email" + devise: + mailer: + confirmation_instructions: + confirm_link_msg: "You can confirm your account email through the link below:" + confirm_account_link: "Confirm my account" + reset_password_instructions: + request_reset_link_msg: "Someone has requested a link to change your password. You can do this through the link below." + password_change_link: "Change my password" + ignore_mail_msg: "If you didn't request this, please ignore this email." + no_changes_msg: "Your password won't change until you access the link above and create a new one." + unlock_instructions: + account_lock_msg: "Your account has been locked due to an excessive number of unsuccessful sign in attempts." + unlock_link_msg: "Click the link below to unlock your account:" + unlock_link: "Unlock my account" + hello: "hello" + welcome: "welcome" diff --git a/config/locales/es.yml b/config/locales/es.yml new file mode 100644 index 000000000..93360f32c --- /dev/null +++ b/config/locales/es.yml @@ -0,0 +1,49 @@ +es: + devise_token_auth: + sessions: + not_confirmed: "Un correo electrónico de confirmación de su cuenta ha sido enviado a '%{email}'. Por favor, siga las instrucciones para validar su cuenta" + bad_credentials: "Identidad o contraseña no válida." + not_supported: "Use POST /sign_in para la conexión. GET no esta disponible." + user_not_found: "Usuario desconocido o no está conectado." + token_validations: + invalid: "Identidad o contraseña no válida." + registrations: + missing_confirm_success_url: "El parámetro 'confirm_success_url' no esta presente." + redirect_url_not_allowed: "Redirección hacia '%{redirect_url}' no esta permitida." + email_already_exists: "Una cuenta ya existe con este correo electrónico '%{email}'" + account_with_uid_destroyed: "La cuenta con el identificador '%{uid}' se ha eliminado." + account_to_destroy_not_found: "No se puede encontrar la cuenta a borrar." + user_not_found: "Usuario no encontrado." + passwords: + missing_email: "Debe incluir un correo electrónico." + missing_redirect_url: "Falta el Url de redirección." + not_allowed_redirect_url: "Redirección hacia '%{redirect_url}' no esta permitida." + sended: "Un correo electrónico ha sido enviado a '%{email}' con las instrucciones para restablecer su contraseña." + user_not_found: "No se pudo encontrar un usuario con este correo electrónico '%{email}'." + password_not_required: "Esta cuenta no requiere contraseña. Iniciar sesión utilizando '%{provider}'." + missing_passwords: "Debe llenar los campos 'Contraseña' y 'Confirmación de contraseña'." + successfully_updated: "Su contraseña ha sido actualizada con éxito." + errors: + messages: + validate_sign_up_params: "Los datos introducidos en la solicitud de acceso no son válidos." + validate_account_update_params: "Los datos introducidos en la solicitud de actualización no son válidos." + not_email: "no es un correo electrónico" + devise: + mailer: + confirmation_instructions: + subject: "Instrucciones de confirmación" + confirm_link_msg: "Para confirmar su cuenta ingrese en el siguiente link:" + confirm_account_link: "Confirmar cuenta" + reset_password_instructions: + subject: "Instrucciones para restablecer su contraseña" + request_reset_link_msg: "Ha solicitado un cambio de contraseña. Para continuar ingrese en el siguiente link:" + password_change_link: "Cambiar contraseña" + ignore_mail_msg: "Por favor ignore este mensaje si no ha solicitado esta acción." + no_changes_msg: "Importante: Su contraseña no será actualizada a menos que ingrese en el link." + unlock_instructions: + subject: "Instrucciones de desbloqueo" + account_lock_msg: "Su cuenta ha sido bloqueada debido a sucesivos intentos de ingresos fallidos" + unlock_link_msg: "Para desbloquear su cuenta ingrese en el siguiente link:" + unlock_link: "Desbloquear cuenta" + hello: "hola" + welcome: "bienvenido" diff --git a/config/locales/fr.yml b/config/locales/fr.yml new file mode 100644 index 000000000..c3f6d5e18 --- /dev/null +++ b/config/locales/fr.yml @@ -0,0 +1,49 @@ +fr: + devise_token_auth: + sessions: + not_confirmed: "Un e-mail de confirmation de votre compte a été envoyé à '%{email}'. Merci de suivre les instructions afin de valider votre compte" + bad_credentials: "Mot de passe ou identifiant invalide." + not_supported: "Utilisez POST /sign_in pour la connexion. GET n'est pas supporté." + user_not_found: "L'utilisateur est inconnu ou n'est pas connecté." + token_validations: + invalid: "Mot de passe ou identifiant invalide." + registrations: + missing_confirm_success_url: "Le paramètre 'confirm_success_url' est manquant." + redirect_url_not_allowed: "Redirection vers '%{redirect_url}' n'est pas autorisée." + email_already_exists: "Un compte existe déjà avec l'adresse e-mail suivante '%{email}'" + account_with_uid_destroyed: "Le compte avec l'identifiant '%{uid}' a été supprimé." + account_to_destroy_not_found: "Le compte à supprimer est introuvable." + user_not_found: "Utilisateur introuvable." + passwords: + missing_email: "Vous devez soumettre un e-mail." + missing_redirect_url: "URL de redirection manquante." + not_allowed_redirect_url: "Redirection vers '%{redirect_url}' n'est pas autorisée." + sended: "Un e-mail a été envoyé à '%{email}' avec les instructions de réinitialisation du mot de passe." + user_not_found: "Impossible de trouver l'utilisateur avec l'adresse e-mail suivante '%{email}'." + password_not_required: "Ce compte ne demande pas de mot de passe. Connectez vous en utilisant '%{provider}'." + missing_passwords: "Vous devez remplir les champs 'Mot de passe' et 'Confirmation de mot de passe'." + successfully_updated: "Votre mot de passe a été correctement mis à jour." + errors: + messages: + validate_sign_up_params: "Les données d'inscription dans le corps de la requête ne sont pas valides." + validate_account_update_params: "Les données de mise à jour dans le corps de la requête ne sont pas valides." + not_email: "n'est pas une adresse e-mail" + devise: + mailer: + confirmation_instructions: + subject: "Instructions de confirmation" + confirm_link_msg: "Vous pouvez confirmer votre compte e-mail via le lien ci-dessous :" + confirm_account_link: "Confirmer mon compte" + reset_password_instructions: + subject: "Instructions de récupération de mot de passe" + request_reset_link_msg: "Quelqu'un a demandé un lien pour changer votre mot de passe. Pour procéder ainsi, suivez le lien ci-dessous." + password_change_link: "Changer mon mot de passe" + ignore_mail_msg: "Si vous n'avez pas demandé cela, veuillez ignorer cet e-mail." + no_changes_msg: "Votre mot de passe ne changera pas tant que vous n'accédez pas au lien ci-dessus pour en créer un nouveau." + unlock_instructions: + subject: "Instructions de déblocage" + account_lock_msg: "Votre compte a été bloqué en raison de nombreuses tentatives de connexion erronées." + unlock_link_msg: "Cliquez sur le lien ci-dessous pour déverrouiller votre compte:" + unlock_link: "Déverrouiller mon compte" + hello: "bonjour" + welcome: "bienvenue" diff --git a/config/locales/it.yml b/config/locales/it.yml new file mode 100644 index 000000000..dfd0eb506 --- /dev/null +++ b/config/locales/it.yml @@ -0,0 +1,46 @@ +it: + devise_token_auth: + sessions: + not_confirmed: "Un'email di conferma è stata mandata al tuo account '%{email}'. Segui le istruzioni nell'email per attivare il tuo account." + bad_credentials: "Credenziali di login non valide. Riprova." + not_supported: "Usa POST /sign_in per eseguire il login. GET non è supportato." + user_not_found: "Utente non trovato o non autenticato." + token_validations: + invalid: "Credenziali di login non valide" + registrations: + missing_confirm_success_url: "Parametro 'confirm_success_url' mancante." + redirect_url_not_allowed: "Redirezione a '%{redirect_url}' non consentita." + email_already_exists: "Esiste già un account per '%{email}'" + account_with_uid_destroyed: "L'account con UID '%{uid}' è stato eliminato." + account_to_destroy_not_found: "Impossibile trovare l'account da eliminare." + user_not_found: "Utente non trovato." + passwords: + missing_email: "Devi fornire un indirizzo email." + missing_redirect_url: "Redirect URL mancante." + not_allowed_redirect_url: "Redirezione a '%{redirect_url}' non consentita." + sended: "E' stata inviata un'email a '%{email}' contenente le istruzioni per reimpostare la password." + user_not_found: "Impossibile trovare un utente con email '%{email}'." + password_not_required: "Questo account non richiede una password. Accedi utilizzando l'account di '%{provider}'." + missing_passwords: "Devi riempire i campi 'Password' e 'Password confirmation'." + successfully_updated: "La tua password è stata aggiornata correttamente." + errors: + messages: + validate_sign_up_params: "Dati di registrazione non validi." + validate_account_update_params: "Dati di aggiornamento dell'account non validi." + not_email: "non è un'email" + devise: + mailer: + confirmation_instructions: + confirm_link_msg: "Puoi confermare il tuo account email cliccando sul seguente link:" + confirm_account_link: "Conferma il mio account" + reset_password_instructions: + request_reset_link_msg: "Qualcuno ha richiesto un link per cambiare la tua password. Puoi farlo cliccando sul seguente link." + password_change_link: "Cambia la mia password" + ignore_mail_msg: "Se non hai richiesto questa operazione, puoi ignorare l'email." + no_changes_msg: "La tua password non cambierà finchè non cliccherai sul link sopra per crearne una nuova." + unlock_instructions: + account_lock_msg: "Il tuo account è stato bloccato a causa di un numero eccessivo di tentativi di accesso non validi." + unlock_link_msg: "Clicca sul seguente link per sbloccare il tuo account:" + unlock_link: "Sblocca il mio account" + hello: "ciao" + welcome: "benvenuto" diff --git a/config/locales/ja.yml b/config/locales/ja.yml new file mode 100644 index 000000000..1b2343127 --- /dev/null +++ b/config/locales/ja.yml @@ -0,0 +1,46 @@ +ja: + devise_token_auth: + sessions: + not_confirmed: "'%{email}' に確認用のメールを送信しました。メール内の説明を読み、アカウントの有効化をしてください。" + bad_credentials: "ログイン用の認証情報が正しくありません。再度お試しください。" + not_supported: "/sign_in に GET はサポートされていません。POST をお使いください。" + user_not_found: "ユーザーが見つからないか、ログインしていません。" + token_validations: + invalid: "ログイン用の認証情報が正しくありません。" + registrations: + missing_confirm_success_url: "'confirm_success_url' パラメータが与えられていません。" + redirect_url_not_allowed: "'%{redirect_url}' へのリダイレクトは許可されていません。" + email_already_exists: "'%{email}' のアカウントはすでに存在しています。" + account_with_uid_destroyed: "'%{uid}' のアカウントは削除されました。" + account_to_destroy_not_found: "削除するアカウントが見つかりません。" + user_not_found: "ユーザーが見つかりません。" + passwords: + missing_email: "メールアドレスが与えられていません。" + missing_redirect_url: "リダイレクト URL が与えられていません。" + not_allowed_redirect_url: "'%{redirect_url}' へのリダイレクトは許可されていません。" + sended: "'%{email}' にパスワードリセットの案内が送信されました。" + user_not_found: "メールアドレス '%{email}' のユーザーが見つかりません。" + password_not_required: "このアカウントはパスワードを要求していません。'%{provider}' を利用してログインしてください。" + missing_passwords: "'Password', 'Password confirmation' パラメータが与えられていません。" + successfully_updated: "パスワードの更新に成功しました。" + errors: + messages: + validate_sign_up_params: "リクエストボディに適切なアカウント新規登録データを送信してください。" + validate_account_update_params: "リクエストボディに適切なアカウント更新のデータを送信してください。" + not_email: "はメールアドレスではありません" + devise: + mailer: + confirmation_instructions: + confirm_link_msg: "下記のリンクからアカウントを有効化できます:" + confirm_account_link: "アカウントを有効化する" + reset_password_instructions: + request_reset_link_msg: "パスワード変更のリクエストが送信されました。下記のリンクからパスワードの変更をできます。" + password_change_link: "パスワードを変更する" + ignore_mail_msg: "もしこの内容に覚えがない場合は、このメールを無視してください。" + no_changes_msg: "上記のリンクにアクセスして新しいパスワードを作成するまで、現在のパスワードは変更されません。" + unlock_instructions: + account_lock_msg: "連続してログインに失敗したため、あなたのアカウントはロックされました。" + unlock_link_msg: "下記のリンクをクリックしてアカウントを有効化してください:" + unlock_link: "アカウントを有効化する" + hello: "こんにちは" + welcome: "ようこそ" diff --git a/config/locales/nl.yml b/config/locales/nl.yml new file mode 100644 index 000000000..7b39022d6 --- /dev/null +++ b/config/locales/nl.yml @@ -0,0 +1,30 @@ +nl: + devise_token_auth: + sessions: + not_confirmed: "Een bevestingsmail is verzonden naar het adres '%{email}'. Volg de instructies in de mail om uw account te activeren." + bad_credentials: 'Ongeldige logingegevens.' + not_supported: "Gebruik POST /sign_in om in te loggen. GET wordt niet ondersteund." + user_not_found: "Gebruiker is niet gevonden of niet ingelogd." + token_validations: + invalid: "Ongeldige logingegevens." + registrations: + missing_confirm_success_url: "Parameter 'confirm_success_url' ontbreekt." + redirect_url_not_allowed: "Redirect naar '%{redirect_url}' niet toegestaan." + email_already_exists: "Er bestaat al een account voor het adres '%{email}'" + account_with_uid_destroyed: "Account met id '%{uid}' is verwijderd." + account_to_destroy_not_found: "Te verwijderen account niet gevonden." + user_not_found: "Gebruiker niet gevonden." + passwords: + missing_email: "Je moet een e-mailadres opgeven." + missing_redirect_url: "Redirect URL ontbreekt." + not_allowed_redirect_url: "Redirect naar '%{redirect_url}' niet toegestaan." + sended: "Er is een e-mail naar '%{email}' verstuurd met instructies om uw wachtwoord te resetten." + user_not_found: "Kan gebruiker met e-mail '%{email}' niet vinden." + password_not_required: "Voor dit account is geen wachtwoord nodig. Log in met uw '%{provider}' account." + missing_passwords: "De velden 'Wachtwoord' en 'Wachtwoord bevestiging' zijn verplicht." + successfully_updated: "Uw wachtwoord is aangepast." + errors: + messages: + validate_sign_up_params: "Gegevens voor aanmaken van het account zijn niet geldig." + validate_account_update_params: "Gegevens voor updaten van het account zijn niet geldig." + not_email: "is geen geldig e-emailadres" diff --git a/config/locales/pl.yml b/config/locales/pl.yml new file mode 100644 index 000000000..5d365567c --- /dev/null +++ b/config/locales/pl.yml @@ -0,0 +1,48 @@ +pl: + devise_token_auth: + sessions: + not_confirmed: "Wiadomość z potwierdzeniem Twojego konta została wysłana na '%{email}'. Proszę postępować zgodnie z wskazówkami znajdującymi się w wiadomości celem aktywacji konta." + bad_credentials: "Nieprawidłowe dane logowania. Proszę spróbować ponownie." + not_supported: "Proszę użyć POST /sign_in do zalogowania. GET nie jest obsługiwany." + user_not_found: "Użytkownik nie został odnaleziony lub nie jest zalogowany." + token_validations: + invalid: "Nieprawidłowe dane logowania." + registrations: + missing_confirm_success_url: "Brak parametru 'confirm_success_url'." + redirect_url_not_allowed: "Przekierowanie na adres '%{redirect_url}' nie jest dozwolone." + email_already_exists: "Konto z adresem '%{email}' już istnieje." + account_with_uid_destroyed: "Konto z uid '%{uid}' zostało usunięte." + account_to_destroy_not_found: "Nie odnaleziono konta do usunięcia." + user_not_found: "Użytkownik nie został odnaleziony." + passwords: + missing_email: "Musisz wprowadzić adres e-mail." + missing_redirect_url: "Brak adresu zwrotnego." + not_allowed_redirect_url: "Przekierowanie na adres '%{redirect_url}' nie jest dozwolone." + sended: "Wiadomość wysłana na adres '%{email}' zawiera instrukcje dotyczące zmiany hasła." + user_not_found: "Nie odnaleziono użytkownika o adresie '%{email}'." + password_not_required: "To konto nie wymaga podania hasła. Zaloguj się używając konta '%{provider}'." + missing_passwords: "Musisz wypełnić wszystkie pola z etykietą 'Hasło' oraz 'Potwierdzenie hasła'." + successfully_updated: "Twoje hasło zostało zaktualizowane." + errors: + validate_sign_up_params: "Proszę dostarczyć odpowiednie dane logowania w ciele zapytania." + validate_account_update_params: "Proszę dostarczyć odpowiednie dane aktualizacji konta w ciele zapytania." + not_email: "nie jest prawidłowym adresem e-mail" + devise: + mailer: + confirmation_instructions: + subject: "Instrukcji potwierdzania" + confirm_link_msg: "Możesz potwierdzić swój e-mail konta poprzez link poniżej :" + confirm_account_link: "Potwierdź swoje konto" + reset_password_instructions: + subject: "Instrukcje resetowania hasła" + request_reset_link_msg: "Ktoś o link do zmiany hasła. Można to zrobić za pośrednictwem linku poniżej." + password_change_link: "Zmień hasło" + ignore_mail_msg: "Jeśli jej nie potrzebuję, zignoruj ​​tę wiadomość." + no_changes_msg: "Twoje hasło nie zmieni, dopóki dostęp powyższy link i utwórz nowy." + unlock_instructions: + subject: "Instrukcje do odblokowania" + account_lock_msg: "Twoje konto zostało zablokowane z powodu zbyt dużej liczby nieudanych znak w próbach." + unlock_link_msg: "Kliknij poniższy link, aby odblokować konto :" + unlock_link: "Odblokować konto" + hello: "halo" + welcome: "witam" diff --git a/config/locales/pt-BR.yml b/config/locales/pt-BR.yml new file mode 100644 index 000000000..c87cfb48a --- /dev/null +++ b/config/locales/pt-BR.yml @@ -0,0 +1,46 @@ +pt-BR: + devise_token_auth: + sessions: + not_confirmed: "Uma mensagem com um link de confirmação foi enviado para seu endereço de e-mail. Você precisa confirmar sua conta antes de continuar." + bad_credentials: "E-mail ou senha inválidos." + not_supported: "Use POST /sign_in para efetuar o login. GET não é suportado." + user_not_found: "Usuário não existe ou não está logado." + token_validations: + invalid: "Dados de login inválidos." + registrations: + missing_confirm_success_url: "Parâmetro 'confirm_success_url' não informado." + redirect_url_not_allowed: "Redirecionamento para '%{redirect_url}' não permitido." + email_already_exists: "Já existe uma conta com o email '%{email}'." + account_with_uid_destroyed: "A conta com uid '%{uid}' foi excluída." + account_to_destroy_not_found: "Não foi possível encontrar a conta para exclusão." + user_not_found: "Usuário não encontrado." + passwords: + missing_email: "Informe o endereço de e-mail." + missing_redirect_url: "URL para redirecionamento não informada." + not_allowed_redirect_url: "Redirecionamento para '%{redirect_url}' não permitido." + sended: "Você receberá um e-mail com instruções sobre como redefinir sua senha." + user_not_found: "Não existe um usuário com o e-mail '%{email}'." + password_not_required: "Esta conta não necessita de uma senha. Faça login utilizando '%{provider}'." + missing_passwords: 'Preencha a senha e a confirmação de senha.' + successfully_updated: "Senha atualizada com sucesso." + errors: + messages: + validate_sign_up_params: "Os dados submetidos na requisição de cadastro são inválidos." + validate_account_update_params: "Os dados submetidos para atualização de conta são inválidos." + not_email: "não é um e-mail" + devise: + mailer: + confirmation_instructions: + confirm_link_msg: "Você pode confirmar a sua conta de e-mail através do link abaixo :" + confirm_account_link: "Confirme conta" + reset_password_instructions: + request_reset_link_msg: "Alguém pediu um link para mudar sua senha. Você pode fazer isso através do link abaixo " + password_change_link: "Alterar a senha" + ignore_mail_msg: "Se você não pediu isso, por favor, ignore este e-mail." + no_changes_msg: "Sua senha não será alterada até que você acessar o link acima e criar um novo." + unlock_instructions: + account_lock_msg: "A sua conta foi bloqueada devido a um número excessivo de sinal de sucesso em tentativas." + unlock_link_msg: "Clique no link abaixo para desbloquear sua conta:" + unlock_link: "Desbloquear minha conta" + hello: "olá" + welcome: "bem-vindo" diff --git a/config/locales/pt.yml b/config/locales/pt.yml new file mode 100644 index 000000000..9b6152af5 --- /dev/null +++ b/config/locales/pt.yml @@ -0,0 +1,48 @@ +pt: + devise_token_auth: + sessions: + not_confirmed: "Uma mensagem com um link de confirmação foi enviado para seu endereço de e-mail. Você precisa confirmar sua conta antes de continuar." + bad_credentials: "E-mail ou senha inválidos." + not_supported: "Use POST /sign_in para efetuar o login. GET não é suportado." + user_not_found: "Utilizador não existe ou não está logado." + token_validations: + invalid: "Dados de login inválidos." + registrations: + missing_confirm_success_url: "Parâmetro 'confirm_success_url' não informado." + redirect_url_not_allowed: "Redirecionamento para '%{redirect_url}' não permitido." + email_already_exists: "Já existe uma conta com o email '%{email}'." + account_with_uid_destroyed: "A conta com uid '%{uid}' foi excluída." + account_to_destroy_not_found: "Não foi possível encontrar a conta para exclusão." + user_not_found: "Utilizador não encontrado." + passwords: + missing_email: "Informe o endereço de e-mail." + missing_redirect_url: "URL para redirecionamento não informada." + not_allowed_redirect_url: "Redirecionamento para '%{redirect_url}' não permitido." + sended: "Você receberá um e-mail com instruções sobre como redefinir sua senha." + user_not_found: "Não existe um utilizador com o e-mail '%{email}'." + password_not_required: "Esta conta não necessita de uma senha. Faça login utilizando '%{provider}'." + missing_passwords: "Preencha a senha e a confirmação de senha." + successfully_updated: "Senha atualizada com sucesso." + errors: + validate_sign_up_params: "Os dados submetidos na requisição de registo são inválidos." + validate_account_update_params: "Os dados submetidos para atualização de conta são inválidos." + not_email: "não é um e-mail" + devise: + mailer: + confirmation_instructions: + subject: "Instruções de confirmação" + confirm_link_msg: "Você pode confirmar a sua conta de e-mail através do link abaixo :" + confirm_account_link: "Confirme conta" + reset_password_instructions: + subject: "Instruções para redefinir sua senha" + request_reset_link_msg: "Alguém pediu um link para mudar sua senha. Você pode fazer isso através do link abaixo " + password_change_link: "Alterar a senha" + ignore_mail_msg: "Se você não pediu isso, por favor, ignore este e-mail." + no_changes_msg: "Sua senha não será alterada até que você acessar o link acima e criar um novo." + unlock_instructions: + subject: "Instruções de desbloqueio" + account_lock_msg: "A sua conta foi bloqueada devido a um número excessivo de sinal de sucesso em tentativas." + unlock_link_msg: "Clique no link abaixo para desbloquear sua conta:" + unlock_link: "Desbloquear minha conta" + hello: "olá" + welcome: "bem-vindo" diff --git a/config/locales/ro.yml b/config/locales/ro.yml new file mode 100644 index 000000000..516b5c13b --- /dev/null +++ b/config/locales/ro.yml @@ -0,0 +1,46 @@ +ro: + devise_token_auth: + sessions: + not_confirmed: "Un email de confirmare a fost trimis către contul tău la '%{email}'. Pentru a-ți activa contul este necesar să urmezi instrucțiunile din acesta." + bad_credentials: "Datele introduse sunt incorecte. Te rugăm să incerci din nou." + not_supported: "Folosește functionalitatea POST /sign_in pentru a te autentifica. GET nu este suportat." + user_not_found: "Utilizatorul nu a fost găsit sau nu este logat în cont." + token_validations: + invalid: "Datele introduse pentru autentificare sunt invalide." + registrations: + missing_confirm_success_url: "Parametrul 'confirm_success_url' lipsește." + redirect_url_not_allowed: "Redirecționarea către '%{redirect_url}' nu este permisă." + email_already_exists: "Un cont cu email '%{email} deja există.'" + account_with_uid_destroyed: "Contul cu UID '%{uid}' a fost șters." + account_to_destroy_not_found: "Nu se poate localiza contul pentru ștergere." + user_not_found: "Utilizatorul nu a fost găsit." + passwords: + missing_email: "Trebuie să introduci o adresă de e-mail." + missing_redirect_url: "URL-ul pentru redirecționare lipsește." + not_allowed_redirect_url: "Redirecționarea către '%{redirect_url}' nu este permisă." + sended: "Un e-mail cu instrucțiuni pentru resetare a parolei a fost trimis către '%{email}'." + user_not_found: "Utilizatorul cu email-ul '%{email}' nu a fost găsit." + password_not_required: "Acest cont nu necesită parolă. Autentifică-te in schimb cu '%{provider}'." + missing_passwords: "Cămpurile 'Parolă' și 'Confirmare parolă' trebuiesc completate." + successfully_updated: "Parola contului a fost schimbată cu succes." + errors: + messages: + validate_sign_up_params: "Trimite credențiale valide în body-ul request-ului." + validate_account_update_params: "Trimite credențiale valide în body-ul request-ului." + not_email: "nu este un email" + devise: + mailer: + confirmation_instructions: + confirm_link_msg: "Poți confirma contul accesănd link-ul de mai jos:" + confirm_account_link: "Confirmă cont" + reset_password_instructions: + request_reset_link_msg: "Cineva a solicitat un link pentru schimbarea parolei contului tău. Poți face această schimbare accesând link-ul de mai jos." + password_change_link: "Schimbă parola" + ignore_mail_msg: "Dacă nu ai solicitat această schimbare ignoră acest e-mail." + no_changes_msg: "Parola ta nu se va schimba până când nu vei accesa link-ul de mai sus și vei crea o nouă parolă." + unlock_instructions: + account_lock_msg: "Contul tău a fost blocat din cauză că cineva a încercat accesarea lui de mai mult ori într-un timp foarte scurt." + unlock_link_msg: "Click pe acest link pentru a debloca contul:" + unlock_link: "Deblochează contul." + hello: "salut" + welcome: "bun venit" diff --git a/config/locales/ru.yml b/config/locales/ru.yml new file mode 100644 index 000000000..13dba216b --- /dev/null +++ b/config/locales/ru.yml @@ -0,0 +1,50 @@ +ru: + devise_token_auth: + sessions: + not_confirmed: "Письмо с подтверждением Вашей учетной записи '%{email}' отправлено на электронную почту. Вы должны следовать инструкциям, приведенным в письме, прежде чем Ваша учетная запись сможет быть активирована" + bad_credentials: "Неверные логин или пароль. Пожалуйста, попробуйте еще раз." + not_supported: "Используйте POST /sign_in для входа. GET запросы не поддерживаются." + user_not_found: "Пользователь не найден или не вошел." + token_validations: + invalid: "Неверные логин или пароль." + registrations: + missing_confirm_success_url: "Отсутствует параметр 'confirm_success_url'." + redirect_url_not_allowed: "Переадресация на '%{redirect_url}' не разрешена." + email_already_exists: "Учетная запись для '%{email}' уже существует" + account_with_uid_destroyed: "Учетная запись с uid '%{uid}' удалена." + account_to_destroy_not_found: "Не удается найти учетную запись для удаления." + user_not_found: "Пользователь не найден." + passwords: + missing_email: "Вы должны указать адрес электронной почты." + missing_redirect_url: "Отсутствует адрес переадресации." + not_allowed_redirect_url: "Переадресация на '%{redirect_url}' не разрешена." + sended: "Инструкция по восстановлению пароля отправлена на Вашу электронную почту '%{email}'." + user_not_found: "Не удается найти пользователя с электронной почтой '%{email}'." + password_not_required: "Эта учетная запись не требует пароля. Войдите используя учетную запись '%{provider}'." + missing_passwords: "Вы должны заполнить поля 'пароль' и 'повторите пароль'." + successfully_updated: "Ваш пароль успешно обновлён." + errors: + messages: + validate_sign_up_params: "Пожалуйста, укажите надлежащие данные для регистрации в теле запроса." + validate_account_update_params: "Пожалуйста, укажите надлежащие данные для обновления учетной записи в теле запроса." + not_email: "не является электронной почтой" + devise: + mailer: + confirmation_instructions: + subject: "Инструкции подтверждения" + confirm_link_msg: "Вы можете подтвердить ваш адрес электронной почты через ссылку ниже :" + confirm_account_link: "Подтвердить свою учетную запись" + reset_password_instructions: + subject: "Инструкции для восстановления пароля" + request_reset_link_msg: "Кто-то запросил ссылку на изменение пароля. Вы можете сделать это через ссылку ниже." + password_change_link: "Изменить пароль" + ignore_mail_msg: "Если Вы не запрашивали это, Вы можете проигнорировать это письмо." + no_changes_msg: "Ваш пароль не изменится, пока вы не откроете ссылку выше и не создадите новый пароль." + unlock_instructions: + subject: "Разблокировать Инструкции" + account_lock_msg: "Ваш аккаунт был заблокирован из-за чрезмерного количества неудачных попыток входа." + unlock_link_msg: "Нажмите на ссылку ниже, чтобы разблокировать свой аккаунт:" + unlock_link: "Разблокировать мою учетную запись" + hello: "Здравствуйте" + welcome: "Добро пожаловать" + diff --git a/config/locales/sq.yml b/config/locales/sq.yml new file mode 100644 index 000000000..cf1f0b278 --- /dev/null +++ b/config/locales/sq.yml @@ -0,0 +1,46 @@ +sq: + devise_token_auth: + sessions: + not_confirmed: "Një email konfirmues është dërguar tek llogaria juaj '%{email}'. Ju duhet të ndiqni udhëzimet në email përpara se të bëhet aktivizimi i llogarisë tuaj." + bad_credentials: "Kredencialet e qasjes nuk janë në rregull. Ju lutemi, provoni përsëri." + not_supported: "Përdorni POST/sign_in për t'u kyçur. GET nuk lejohet në këtë rast." + user_not_found: "Përdoruesi nuk u gjet ose nuk është i kyçur." + token_validations: + invalid: "Kredencialet për kyçje nuk janë në rregull." + registrations: + missing_confirm_success_url: "Mungon parametri 'confirm_success_url'." + redirect_url_not_allowed: "Nuk lejohet shkuarja tek adresa '%{redirect_url}'." + email_already_exists: "Një llogari është regjistruar më parë me adresën '%{email}'" + account_with_uid_destroyed: "Llogaria me UID-në '%{uid}' është fshirë." + account_to_destroy_not_found: "Nuk u gjet llogaria për fshirje." + user_not_found: "Përdoruesi nuk u gjet." + passwords: + missing_email: "Ju duhet të jepni një email adresë." + missing_redirect_url: "Mungon URL-ja për ridërgim." + not_allowed_redirect_url: "Nuk lejohet shkuarja tek URL-ja '%{redirect_url}'." + sended: "Një email është dërguar tek email adresa '%{email}' që përmban udhëzime për rikthim të fjalëkalimit tuaj." + user_not_found: "Nuk u gjet përdoruesi me email adresën '%{email}'." + password_not_required: "Kjo llogari nuk kërkon fjalëkalim. Në vend të fjalëkalimit, përdorni llogarinë '%{provider}'." + missing_passwords: "Ju duhet t'i mbushni fushat e etiketuara si 'Fjalëkalimi' dhe 'Konfirmo fjalëkalimin'." + successfully_updated: "Fjalëkalimi juaj është ndryshuar me sukses." + errors: + messages: + validate_sign_up_params: "Ju lutemi, dërgoni të dhëna të duhura në trupin e kërkesës." + validate_account_update_params: "Ju lutemi, dërgoni të dhëna të duhura për ndryshim në trupin e kërkesës." + not_email: "nuk është email" + devise: + mailer: + confirmation_instructions: + confirm_link_msg: "Ju mund ta konfirmoni email adresën e llogarisë tuaj përmes lidhjes më poshtë:" + confirm_account_link: "Konfirmo llogarinë time" + reset_password_instructions: + request_reset_link_msg: "Dikush ka kërkuar një lidhje për të ndryshuar fjalëkalimin tuaj. Ju mund ta bëni këtë përmes lidhjes më poshtë." + password_change_link: "Ndrysho fjalëkalimin tim" + ignore_mail_msg: "Nëse nuk e keni kërkuar këtë, ju lutemi injorojeni këtë email." + no_changes_msg: "Fjalëkalimi juaj nuk do të ndryshohet derisa t'i qaseni lidhjes më sipër dhe ta krijoni një fjalëkalim të ri." + unlock_instructions: + account_lock_msg: "Llogaria juaj është bllokuar për shkak të numrit të tepërt të përpjekjeve të pa suksesshme për t'u kyçur." + unlock_link_msg: "Klikoni lidhjen më poshtë për të zhbllokuar llogarinë tuaj:" + unlock_link: "Zhblloko llogarinë time" + hello: "tungjatjeta" + welcome: "mirësevini" diff --git a/config/locales/zh-CN.yml b/config/locales/zh-CN.yml new file mode 100644 index 000000000..8a34f5f00 --- /dev/null +++ b/config/locales/zh-CN.yml @@ -0,0 +1,46 @@ +zh-CN: + devise_token_auth: + sessions: + not_confirmed: "您将在几分钟后收到一封电子邮件'%{email}',内有验证账号的步骤说明" + bad_credentials: "不正确的登录信息,请重试" + not_supported: "请使用 POST /sign_in 进行登录. GET 是不支持的." + user_not_found: "没有找到账号或没有成功登录" + token_validations: + invalid: "不正确的登录资料" + registrations: + missing_confirm_success_url: "缺少数据 'confirm_success_url'" + redirect_url_not_allowed: "不支持转向到 '%{redirect_url}'" + email_already_exists: "邮箱'%{email}'已被使用" + account_with_uid_destroyed: "账号 '%{uid}' 已被移除。" + account_to_destroy_not_found: "无法找到目标帐号。" + user_not_found: "找不到帐号。" + passwords: + missing_email: "必需提供邮箱。" + missing_redirect_url: "欠缺 redirect URL." + not_allowed_redirect_url: "不支持转向到 '%{redirect_url}'" + sended: "您将在几分钟后收到一封电子邮件'%{email},内含可重新设定密码的链接。" + user_not_found: "找不到帐号 '%{email}'。" + password_not_required: "这不是一个需要密码的帐号. 请使用 '%{provider}' 进行登入" + missing_passwords: "必需填写'密码'与'确认密码'。" + successfully_updated: "您的密码已被修改。" + errors: + messages: + validate_sign_up_params: "请在request body中填入有效的注册内容" + validate_account_update_params: "请在request body中填入有效的更新帐号资料" + not_email: "这不是一个合适的邮箱。" + devise: + mailer: + confirmation_instructions: + confirm_link_msg: "可以使用下面的链接确定你的邮箱" + confirm_account_link: "确定你的帐号" + reset_password_instructions: + request_reset_link_msg: "已申请修改您的密码,你可以用下面的链接进入" + password_change_link: "修改我的密码" + ignore_mail_msg: "如你没有申请,请忽略" + no_changes_msg: "在你点击上面链接前,你的密码都没有改变" + unlock_instructions: + account_lock_msg: "由于多次登入失败,我们已锁定你的帐号" + unlock_link_msg: "可以使用下面的链接解锁你的帐号" + unlock_link: "解锁帐号" + hello: "你好" + welcome: "欢迎" diff --git a/config/locales/zh-HK.yml b/config/locales/zh-HK.yml new file mode 100644 index 000000000..b541f8459 --- /dev/null +++ b/config/locales/zh-HK.yml @@ -0,0 +1,48 @@ +# Additional translations at https://github.com/plataformatec/devise/wiki/I18n + +zh-TW: + devise_token_auth: + sessions: + not_confirmed: "您將在幾分鐘後收到一封電子郵件'%{email}',內有驗證帳號的步驟說明。" + bad_credentials: "不正確的登入資料。請重試。" + not_supported: "請使用 POST /sign_in 進行登入. GET 是不支援的." + user_not_found: "未能找到帳號或未能成功登入。" + token_validations: + invalid: "不正確的登入資料。" + registrations: + missing_confirm_success_url: "欠缺數值 'confirm_success_url'" + redirect_url_not_allowed: "不支援轉向到'%{redirect_url}'" + email_already_exists: "電郵'%{email}'已被使用" + account_with_uid_destroyed: "帳號 '%{uid}' 已被移除。" + account_to_destroy_not_found: "無法找到目標帳號。" + user_not_found: "找不到帳號。" + passwords: + missing_email: "必需提供電郵。" + missing_redirect_url: "欠缺 redirect URL." + not_allowed_redirect_url: "不支援轉向到 '%{redirect_url}'" + sended: "您將在幾分鐘後收到一封電子郵件'%{email},內含可重新設定密碼連結的電子郵件。" + user_not_found: "找不到帳號 '%{email}'。" + password_not_required: "這不是一個需要密碼的帳號. 請使用 '%{provider}' 進行登入" + missing_passwords: "必需填寫'密碼'與'確認密碼'。" + successfully_updated: "您的密碼已被修改。" + errors: + messages: + validate_sign_up_params: "請在request body中填入有效的註冊內容" + validate_account_update_params: "請在request body中填入有效的更新帳號資料" + not_email: "這不是一個合適的電郵。" + devise: + mailer: + confirmation_instructions: + confirm_link_msg: "可以使用下面連結確定你的電郵" + confirm_account_link: "確定你的帳號" + reset_password_instructions: + request_reset_link_msg: "已申請修改您的密碼,你可以用下面連結進入" + password_change_link: "修改我的密碼" + ignore_mail_msg: "如你沒有申請,請忽略" + no_changes_msg: "在你點擊上面連結前,你的密碼都沒有改變" + unlock_instructions: + account_lock_msg: "由於多失敗登入,我們已鎖定你的帳號" + unlock_link_msg: "可以使用下面連結解鎖你的帳號" + unlock_link: "解鎖帳號" + hello: "你好" + welcome: "歡迎" diff --git a/config/locales/zh-TW.yml b/config/locales/zh-TW.yml new file mode 100644 index 000000000..b541f8459 --- /dev/null +++ b/config/locales/zh-TW.yml @@ -0,0 +1,48 @@ +# Additional translations at https://github.com/plataformatec/devise/wiki/I18n + +zh-TW: + devise_token_auth: + sessions: + not_confirmed: "您將在幾分鐘後收到一封電子郵件'%{email}',內有驗證帳號的步驟說明。" + bad_credentials: "不正確的登入資料。請重試。" + not_supported: "請使用 POST /sign_in 進行登入. GET 是不支援的." + user_not_found: "未能找到帳號或未能成功登入。" + token_validations: + invalid: "不正確的登入資料。" + registrations: + missing_confirm_success_url: "欠缺數值 'confirm_success_url'" + redirect_url_not_allowed: "不支援轉向到'%{redirect_url}'" + email_already_exists: "電郵'%{email}'已被使用" + account_with_uid_destroyed: "帳號 '%{uid}' 已被移除。" + account_to_destroy_not_found: "無法找到目標帳號。" + user_not_found: "找不到帳號。" + passwords: + missing_email: "必需提供電郵。" + missing_redirect_url: "欠缺 redirect URL." + not_allowed_redirect_url: "不支援轉向到 '%{redirect_url}'" + sended: "您將在幾分鐘後收到一封電子郵件'%{email},內含可重新設定密碼連結的電子郵件。" + user_not_found: "找不到帳號 '%{email}'。" + password_not_required: "這不是一個需要密碼的帳號. 請使用 '%{provider}' 進行登入" + missing_passwords: "必需填寫'密碼'與'確認密碼'。" + successfully_updated: "您的密碼已被修改。" + errors: + messages: + validate_sign_up_params: "請在request body中填入有效的註冊內容" + validate_account_update_params: "請在request body中填入有效的更新帳號資料" + not_email: "這不是一個合適的電郵。" + devise: + mailer: + confirmation_instructions: + confirm_link_msg: "可以使用下面連結確定你的電郵" + confirm_account_link: "確定你的帳號" + reset_password_instructions: + request_reset_link_msg: "已申請修改您的密碼,你可以用下面連結進入" + password_change_link: "修改我的密碼" + ignore_mail_msg: "如你沒有申請,請忽略" + no_changes_msg: "在你點擊上面連結前,你的密碼都沒有改變" + unlock_instructions: + account_lock_msg: "由於多失敗登入,我們已鎖定你的帳號" + unlock_link_msg: "可以使用下面連結解鎖你的帳號" + unlock_link: "解鎖帳號" + hello: "你好" + welcome: "歡迎" diff --git a/config/routes.rb b/config/routes.rb deleted file mode 100644 index 90f2f4897..000000000 --- a/config/routes.rb +++ /dev/null @@ -1,5 +0,0 @@ -Rails.application.routes.draw do - if defined?(::OmniAuth) - get "#{::OmniAuth::config.path_prefix}/:provider/callback", to: "devise_token_auth/omniauth_callbacks#redirect_callbacks" - end -end diff --git a/devise_token_auth.gemspec b/devise_token_auth.gemspec index 27f1585d2..c49c1296b 100644 --- a/devise_token_auth.gemspec +++ b/devise_token_auth.gemspec @@ -16,9 +16,10 @@ Gem::Specification.new do |s| s.files = Dir["{app,config,db,lib}/**/*", "LICENSE", "Rakefile", "README.md"] s.test_files = Dir["test/**/*"] + s.test_files.reject! { |file| file.match(/[.log|.sqlite3]$/) } - s.add_dependency "rails", "~> 4.1" - s.add_dependency "devise", "~> 3.3" + s.add_dependency "rails", "< 6" + s.add_dependency "devise", "> 3.5.2", "< 4.4" s.add_development_dependency "sqlite3", "~> 1.3" s.add_development_dependency 'pg' diff --git a/lib/devise_token_auth.rb b/lib/devise_token_auth.rb index 3a7865ab3..7ba990e61 100644 --- a/lib/devise_token_auth.rb +++ b/lib/devise_token_auth.rb @@ -2,6 +2,7 @@ require "devise_token_auth/engine" require "devise_token_auth/controllers/helpers" require "devise_token_auth/controllers/url_helpers" +require "devise_token_auth/url" module DeviseTokenAuth end diff --git a/lib/devise_token_auth/controllers/helpers.rb b/lib/devise_token_auth/controllers/helpers.rb index f7d233a66..368b78aa8 100644 --- a/lib/devise_token_auth/controllers/helpers.rb +++ b/lib/devise_token_auth/controllers/helpers.rb @@ -21,8 +21,8 @@ module ClassMethods # current_bloggers # Currently signed in user and admin # # Use: - # before_filter :authenticate_blogger! # Redirects unless either a user or an admin are authenticated - # before_filter ->{ authenticate_blogger! :admin } # Redirects to the admin login page + # before_action :authenticate_blogger! # Redirects unless either a user or an admin are authenticated + # before_action ->{ authenticate_blogger! :admin } # Redirects to the admin login page # current_blogger :user # Preferably returns a User if one is signed in # def devise_token_auth_group(group_name, opts={}) @@ -36,6 +36,12 @@ def authenticate_#{group_name}!(favourite=nil, opts={}) mappings.each do |mapping| set_user_by_token(mapping) end + + unless current_#{group_name} + return render json: { + errors: [I18n.t('devise.failure.unauthenticated')] + }, status: 401 + end end end @@ -61,7 +67,9 @@ def current_#{group_name.to_s.pluralize} end.compact end - helper_method "current_#{group_name}", "current_#{group_name.to_s.pluralize}", "#{group_name}_signed_in?" + if respond_to?(:helper_method) + helper_method "current_#{group_name}", "current_#{group_name.to_s.pluralize}", "#{group_name}_signed_in?" + end METHODS end @@ -72,7 +80,7 @@ def log_process_action(payload) end # Define authentication filters and accessor helpers based on mappings. - # These filters should be used inside the controllers as before_filters, + # These filters should be used inside the controllers as before_actions, # so you can control the scope of the user who should be signed in to # access that specific controller/action. # Example: @@ -92,8 +100,8 @@ def log_process_action(payload) # admin_session # Session data available only to the admin scope # # Use: - # before_filter :authenticate_user! # Tell devise to use :user map - # before_filter :authenticate_admin! # Tell devise to use :admin map + # before_action :authenticate_user! # Tell devise to use :user map + # before_action :authenticate_admin! # Tell devise to use :admin map # def self.define_helpers(mapping) #:nodoc: mapping = mapping.name @@ -102,7 +110,7 @@ def self.define_helpers(mapping) #:nodoc: def authenticate_#{mapping}! unless current_#{mapping} return render json: { - errors: ["Authorized users only."] + errors: [I18n.t('devise.failure.unauthenticated')] }, status: 401 end end @@ -121,7 +129,9 @@ def #{mapping}_session METHODS ActiveSupport.on_load(:action_controller) do - helper_method "current_#{mapping}", "#{mapping}_signed_in?", "#{mapping}_session" + if respond_to?(:helper_method) + helper_method "current_#{mapping}", "#{mapping}_signed_in?", "#{mapping}_session" + end end end end diff --git a/lib/devise_token_auth/engine.rb b/lib/devise_token_auth/engine.rb index c88c5d9ba..558e6dbf0 100644 --- a/lib/devise_token_auth/engine.rb +++ b/lib/devise_token_auth/engine.rb @@ -10,16 +10,79 @@ class Engine < ::Rails::Engine end mattr_accessor :change_headers_on_each_request, + :max_number_of_devices, :token_lifespan, :batch_request_buffer_throttle, - :omniauth_prefix + :omniauth_prefix, + :default_confirm_success_url, + :default_password_reset_url, + :redirect_whitelist, + :check_current_password_before_update, + :enable_standard_devise_support, + :remove_tokens_after_password_reset, + :default_callbacks, + :headers_names - self.change_headers_on_each_request = true - self.token_lifespan = 2.weeks - self.batch_request_buffer_throttle = 5.seconds - self.omniauth_prefix = '/omniauth' + self.change_headers_on_each_request = true + self.max_number_of_devices = 10 + self.token_lifespan = 2.weeks + self.batch_request_buffer_throttle = 5.seconds + self.omniauth_prefix = '/omniauth' + self.default_confirm_success_url = nil + self.default_password_reset_url = nil + self.redirect_whitelist = nil + self.check_current_password_before_update = false + self.enable_standard_devise_support = false + self.remove_tokens_after_password_reset = false + self.default_callbacks = true + self.headers_names = {:'access-token' => 'access-token', + :'client' => 'client', + :'expiry' => 'expiry', + :'uid' => 'uid', + :'token-type' => 'token-type' } def self.setup(&block) yield self + + Rails.application.config.after_initialize do + if defined?(::OmniAuth) + ::OmniAuth::config.path_prefix = Devise.omniauth_path_prefix = self.omniauth_prefix + + + # Omniauth currently does not pass along omniauth.params upon failure redirect + # see also: https://github.com/intridea/omniauth/issues/626 + OmniAuth::FailureEndpoint.class_eval do + def redirect_to_failure + message_key = env['omniauth.error.type'] + origin_query_param = env['omniauth.origin'] ? "&origin=#{CGI.escape(env['omniauth.origin'])}" : "" + strategy_name_query_param = env['omniauth.error.strategy'] ? "&strategy=#{env['omniauth.error.strategy'].name}" : "" + extra_params = env['omniauth.params'] ? "&#{env['omniauth.params'].to_query}" : "" + new_path = "#{env['SCRIPT_NAME']}#{OmniAuth.config.path_prefix}/failure?message=#{message_key}#{origin_query_param}#{strategy_name_query_param}#{extra_params}" + Rack::Response.new(["302 Moved"], 302, 'Location' => new_path).finish + end + end + + + # Omniauth currently removes omniauth.params during mocked requests + # see also: https://github.com/intridea/omniauth/pull/812 + OmniAuth::Strategy.class_eval do + def mock_callback_call + setup_phase + @env['omniauth.origin'] = session.delete('omniauth.origin') + @env['omniauth.origin'] = nil if env['omniauth.origin'] == '' + @env['omniauth.params'] = session.delete('omniauth.params') || {} + mocked_auth = OmniAuth.mock_auth_for(name.to_s) + if mocked_auth.is_a?(Symbol) + fail!(mocked_auth) + else + @env['omniauth.auth'] = mocked_auth + OmniAuth.config.before_callback_phase.call(@env) if OmniAuth.config.before_callback_phase + call_app! + end + end + end + + end + end end end diff --git a/lib/devise_token_auth/rails/routes.rb b/lib/devise_token_auth/rails/routes.rb index 41cceedb2..69f3541e6 100644 --- a/lib/devise_token_auth/rails/routes.rb +++ b/lib/devise_token_auth/rails/routes.rb @@ -12,54 +12,104 @@ def mount_devise_token_auth_for(resource, opts) confirmations_ctrl = opts[:controllers][:confirmations] || "devise_token_auth/confirmations" token_validations_ctrl = opts[:controllers][:token_validations] || "devise_token_auth/token_validations" omniauth_ctrl = opts[:controllers][:omniauth_callbacks] || "devise_token_auth/omniauth_callbacks" + unlocks_ctrl = opts[:controllers][:unlocks] # define devise controller mappings controllers = {:sessions => sessions_ctrl, :registrations => registrations_ctrl, :passwords => passwords_ctrl, - :confirmations => confirmations_ctrl, - :omniauth_callbacks => omniauth_ctrl} + :confirmations => confirmations_ctrl} + + controllers[:unlocks] = unlocks_ctrl if unlocks_ctrl # remove any unwanted devise modules opts[:skip].each{|item| controllers.delete(item)} - scope opts[:at] do - devise_for resource.pluralize.underscore.to_sym, - :class_name => resource, - :module => :devise, - :path => "", - :controllers => controllers + devise_for resource.pluralize.underscore.gsub('/', '_').to_sym, + :class_name => resource, + :module => :devise, + :path => "#{opts[:at]}", + :controllers => controllers, + :skip => opts[:skip] + [:omniauth_callbacks] + + unnest_namespace do + # get full url path as if it were namespaced + full_path = "#{@scope[:path]}/#{opts[:at]}" + + # get namespace name + namespace_name = @scope[:as] + + # clear scope so controller routes aren't namespaced + @scope = ActionDispatch::Routing::Mapper::Scope.new( + path: "", + shallow_path: "", + constraints: {}, + defaults: {}, + options: {}, + parent: nil + ) - devise_scope resource.underscore.to_sym do + mapping_name = resource.underscore.gsub('/', '_') + mapping_name = "#{namespace_name}_#{mapping_name}" if namespace_name + + devise_scope mapping_name.to_sym do # path to verify token validity get "validate_token", to: "#{token_validations_ctrl}#validate_token" - + get "validate_external_token", to: "#{token_validations_ctrl}#validate_external_token" + get "#{full_path}/validate_token", controller: "#{token_validations_ctrl}", action: "validate_token" # omniauth routes. only define if omniauth is installed and not skipped. - if defined?(::OmniAuth) and not opts[:skip].include?(:omniauth_callbacks) - get "failure", to: "#{omniauth_ctrl}#omniauth_failure" - get ":provider/callback", to: "#{omniauth_ctrl}#omniauth_success" + if defined?(::OmniAuth) && !opts[:skip].include?(:omniauth_callbacks) + match "#{full_path}/failure", controller: omniauth_ctrl, action: "omniauth_failure", via: [:get] + match "#{full_path}/:provider/callback", controller: omniauth_ctrl, action: "omniauth_success", via: [:get] + + match "#{DeviseTokenAuth.omniauth_prefix}/:provider/callback", controller: omniauth_ctrl, action: "redirect_callbacks", via: [:get, :post] + match "#{DeviseTokenAuth.omniauth_prefix}/failure", controller: omniauth_ctrl, action: "omniauth_failure", via: [:get, :post] # preserve the resource class thru oauth authentication by setting name of # resource as "resource_class" param - match ":provider", to: redirect{|params, request| + match "#{full_path}/:provider", to: redirect{|params, request| # get the current querystring qs = CGI::parse(request.env["QUERY_STRING"]) # append name of current resource qs["resource_class"] = [resource] + qs["namespace_name"] = [namespace_name] if namespace_name + + set_omniauth_path_prefix!(DeviseTokenAuth.omniauth_prefix) + + redirect_params = {}.tap {|hash| qs.each{|k, v| hash[k] = v.first}} + + if DeviseTokenAuth.redirect_whitelist + redirect_url = request.params['auth_origin_url'] + unless DeviseTokenAuth::Url.whitelisted?(redirect_url) + message = I18n.t( + 'devise_token_auth.registrations.redirect_url_not_allowed', + redirect_url: redirect_url + ) + redirect_params['message'] = message + next "#{::OmniAuth.config.path_prefix}/failure?#{redirect_params.to_param}" + end + end # re-construct the path for omniauth - "#{::OmniAuth::config.path_prefix}/#{params[:provider]}?#{{}.tap {|hash| qs.each{|k, v| hash[k] = v.first}}.to_param}" + "#{::OmniAuth.config.path_prefix}/#{params[:provider]}?#{redirect_params.to_param}" }, via: [:get] end end end end + # this allows us to use namespaced paths without namespacing the routes + def unnest_namespace + current_scope = @scope.dup + yield + ensure + @scope = current_scope + end + # ignore error about omniauth/multiple model support def set_omniauth_path_prefix!(path_prefix) ::OmniAuth.config.path_prefix = path_prefix end - end end diff --git a/lib/devise_token_auth/url.rb b/lib/devise_token_auth/url.rb new file mode 100644 index 000000000..ad4699e3c --- /dev/null +++ b/lib/devise_token_auth/url.rb @@ -0,0 +1,37 @@ +module DeviseTokenAuth::Url + + def self.generate(url, params = {}) + uri = URI(url) + + res = "#{uri.scheme}://#{uri.host}" + res += ":#{uri.port}" if (uri.port && uri.port != 80 && uri.port != 443) + res += "#{uri.path}" if uri.path + query = [uri.query, params.to_query].reject(&:blank?).join('&') + res += "?#{query}" + res += "##{uri.fragment}" if uri.fragment + + return res + end + + def self.whitelisted?(url) + !!DeviseTokenAuth.redirect_whitelist.find { |pattern| !!Wildcat.new(pattern).match(url) } + end + + + # wildcard convenience class + class Wildcat + def self.parse_to_regex(str) + escaped = Regexp.escape(str).gsub('\*','.*?') + Regexp.new("^#{escaped}$", Regexp::IGNORECASE) + end + + def initialize(str) + @regex = self.class.parse_to_regex(str) + end + + def match(str) + !!@regex.match(str) + end + end + +end diff --git a/lib/devise_token_auth/version.rb b/lib/devise_token_auth/version.rb index fa05a15c1..c504dcf71 100644 --- a/lib/devise_token_auth/version.rb +++ b/lib/devise_token_auth/version.rb @@ -1,3 +1,3 @@ module DeviseTokenAuth - VERSION = "0.1.30.beta5" + VERSION = "0.1.42" end diff --git a/lib/generators/devise_token_auth/USAGE b/lib/generators/devise_token_auth/USAGE index a022bce66..bc9c1da1a 100644 --- a/lib/generators/devise_token_auth/USAGE +++ b/lib/generators/devise_token_auth/USAGE @@ -1,6 +1,6 @@ Description: This generator will install all the necessary configuration and migration - files for the devies_token_auth gem. See + files for the devise_token_auth gem. See https://github.com/lynndylanhurley/devise_token_auth for more information. Arguments: @@ -8,7 +8,7 @@ Arguments: # 'User' MOUNT_PATH # The path at which to mount the authentication routes. Default is # 'auth'. More detail documentation is here: - # https://github.com/lynndylanhurley/devise_token_auth#usage + # https://github.com/lynndylanhurley/devise_token_auth#usage-tldr Example: rails generate devise_token_auth:install User auth @@ -28,4 +28,4 @@ Example: The following line will be inserted at the top of 'config/routes.rb' if it does not already exist: - mount_devise_token_auth_for "User", at: '/auth' + mount_devise_token_auth_for "User", at: 'auth' diff --git a/lib/generators/devise_token_auth/install_generator.rb b/lib/generators/devise_token_auth/install_generator.rb index 8bf15a0cb..0518857f0 100644 --- a/lib/generators/devise_token_auth/install_generator.rb +++ b/lib/generators/devise_token_auth/install_generator.rb @@ -5,7 +5,7 @@ class InstallGenerator < Rails::Generators::Base source_root File.expand_path('../templates', __FILE__) argument :user_class, type: :string, default: "User" - argument :mount_path, type: :string, default: '/auth' + argument :mount_path, type: :string, default: 'auth' def create_initializer_file copy_file("devise_token_auth.rb", "config/initializers/devise_token_auth.rb") @@ -29,7 +29,13 @@ def create_user_model else inclusion = "include DeviseTokenAuth::Concerns::User" unless parse_file_for_line(fname, inclusion) - inject_into_file fname, after: "class #{user_class} < ActiveRecord::Base\n" do <<-'RUBY' + + active_record_needle = (Rails::VERSION::MAJOR == 5) ? 'ApplicationRecord' : 'ActiveRecord::Base' + inject_into_file fname, after: "class #{user_class} < #{active_record_needle}\n" do <<-'RUBY' + # Include default devise modules. + devise :database_authenticatable, :registerable, + :recoverable, :rememberable, :trackable, :validatable, + :confirmable, :omniauthable include DeviseTokenAuth::Concerns::User RUBY end @@ -44,6 +50,11 @@ def include_controller_concerns if File.exist?(File.join(destination_root, fname)) if parse_file_for_line(fname, line) say_status("skipped", "Concern is already included in the application controller.") + elsif is_rails_api? + inject_into_file fname, after: "class ApplicationController < ActionController::API\n" do <<-'RUBY' + include DeviseTokenAuth::Concerns::SetUserByToken + RUBY + end else inject_into_file fname, after: "class ApplicationController < ActionController::Base\n" do <<-'RUBY' include DeviseTokenAuth::Concerns::SetUserByToken @@ -111,5 +122,39 @@ def parse_file_for_line(filename, str) end match end + + def is_rails_api? + fname = "app/controllers/application_controller.rb" + line = "class ApplicationController < ActionController::API" + parse_file_for_line(fname, line) + end + + def json_supported_database? + (postgres? && postgres_correct_version?) || (mysql? && mysql_correct_version?) + end + + def postgres? + database_name == 'ActiveRecord::ConnectionAdapters::PostgreSQLAdapter' + end + + def postgres_correct_version? + database_version > '9.3' + end + + def mysql? + database_name == 'ActiveRecord::ConnectionAdapters::MysqlAdapter' + end + + def mysql_correct_version? + database_version > '5.7.7' + end + + def database_name + ActiveRecord::Base.connection.class.name + end + + def database_version + ActiveRecord::Base.connection.select_value('SELECT VERSION()') + end end end diff --git a/lib/generators/devise_token_auth/templates/devise_token_auth.rb b/lib/generators/devise_token_auth/templates/devise_token_auth.rb index a34435e15..af7acd737 100644 --- a/lib/generators/devise_token_auth/templates/devise_token_auth.rb +++ b/lib/generators/devise_token_auth/templates/devise_token_auth.rb @@ -3,20 +3,46 @@ # client is responsible for keeping track of the changing tokens. Change # this to false to prevent the Authorization header from changing after # each request. - #config.change_headers_on_each_request = true + # config.change_headers_on_each_request = true # By default, users will need to re-authenticate after 2 weeks. This setting # determines how long tokens will remain valid after they are issued. - #config.token_lifespan = 2.weeks + # config.token_lifespan = 2.weeks + + # Sets the max number of concurrent devices per user, which is 10 by default. + # After this limit is reached, the oldest tokens will be removed. + # config.max_number_of_devices = 10 # Sometimes it's necessary to make several requests to the API at the same # time. In this case, each request in the batch will need to share the same # auth token. This setting determines how far apart the requests can be while # still using the same auth token. - #config.batch_request_buffer_throttle = 5.seconds + # config.batch_request_buffer_throttle = 5.seconds # This route will be the prefix for all oauth2 redirect callbacks. For # example, using the default '/omniauth', the github oauth2 provider will # redirect successful authentications to '/omniauth/github/callback' - #config.omniauth_prefix = "/omniauth" + # config.omniauth_prefix = "/omniauth" + + # By default sending current password is not needed for the password update. + # Uncomment to enforce current_password param to be checked before all + # attribute updates. Set it to :password if you want it to be checked only if + # password is updated. + # config.check_current_password_before_update = :attributes + + # By default we will use callbacks for single omniauth. + # It depends on fields like email, provider and uid. + # config.default_callbacks = true + + # Makes it possible to change the headers names + # config.headers_names = {:'access-token' => 'access-token', + # :'client' => 'client', + # :'expiry' => 'expiry', + # :'uid' => 'uid', + # :'token-type' => 'token-type' } + + # By default, only Bearer Token authentication is implemented out of the box. + # If, however, you wish to integrate with legacy Devise authentication, you can + # do so by enabling this flag. NOTE: This feature is highly experimental! + # config.enable_standard_devise_support = false end diff --git a/lib/generators/devise_token_auth/templates/devise_token_auth_create_users.rb.erb b/lib/generators/devise_token_auth/templates/devise_token_auth_create_users.rb.erb index a384daace..b1aec3236 100644 --- a/lib/generators/devise_token_auth/templates/devise_token_auth_create_users.rb.erb +++ b/lib/generators/devise_token_auth/templates/devise_token_auth_create_users.rb.erb @@ -1,8 +1,8 @@ -class DeviseTokenAuthCreate<%= user_class.pluralize %> < ActiveRecord::Migration +class DeviseTokenAuthCreate<%= user_class.pluralize %> < ActiveRecord::Migration<%= '[' << Rails::VERSION::STRING[0..2] << ']'%> def change create_table(:<%= user_class.pluralize.underscore %>) do |t| ## Required - t.string :provider, :null => false + t.string :provider, :null => false, :default => "email" t.string :uid, :null => false, :default => "" ## Database authenticatable @@ -40,15 +40,15 @@ class DeviseTokenAuthCreate<%= user_class.pluralize %> < ActiveRecord::Migration t.string :email ## Tokens - t.text :tokens + <%= json_supported_database? ? 't.json :tokens' : 't.text :tokens' %> t.timestamps end - add_index :<%= user_class.pluralize.underscore %>, :email - add_index :<%= user_class.pluralize.underscore %>, [:uid, :provider], :unique => true - add_index :<%= user_class.pluralize.underscore %>, :reset_password_token, :unique => true - # add_index :<%= user_class.pluralize.underscore %>, :confirmation_token, :unique => true - # add_index :<%= user_class.pluralize.underscore %>, :unlock_token, :unique => true + add_index :<%= user_class.pluralize.underscore %>, :email, unique: true + add_index :<%= user_class.pluralize.underscore %>, [:uid, :provider], unique: true + add_index :<%= user_class.pluralize.underscore %>, :reset_password_token, unique: true + add_index :<%= user_class.pluralize.underscore %>, :confirmation_token, unique: true + # add_index :<%= user_class.pluralize.underscore %>, :unlock_token, unique: true end end diff --git a/lib/generators/devise_token_auth/templates/user.rb b/lib/generators/devise_token_auth/templates/user.rb index 461c3c431..2eeb0fa96 100644 --- a/lib/generators/devise_token_auth/templates/user.rb +++ b/lib/generators/devise_token_auth/templates/user.rb @@ -1,3 +1,7 @@ class <%= user_class %> < ActiveRecord::Base + # Include default devise modules. + devise :database_authenticatable, :registerable, + :recoverable, :rememberable, :trackable, :validatable, + :confirmable, :omniauthable include DeviseTokenAuth::Concerns::User end diff --git a/test/controllers/custom/custom_confirmations_controller_test.rb b/test/controllers/custom/custom_confirmations_controller_test.rb new file mode 100644 index 000000000..9fbde6043 --- /dev/null +++ b/test/controllers/custom/custom_confirmations_controller_test.rb @@ -0,0 +1,26 @@ +require 'test_helper' + +class Custom::ConfirmationsControllerTest < ActionController::TestCase + + describe Custom::ConfirmationsController do + + before do + @redirect_url = Faker::Internet.url + @new_user = users(:unconfirmed_email_user) + @new_user.send_confirmation_instructions({ + redirect_url: @redirect_url + }) + @mail = ActionMailer::Base.deliveries.last + @token = @mail.body.match(/confirmation_token=([^&]*)&/)[1] + @client_config = @mail.body.match(/config=([^&]*)&/)[1] + + get :show, {confirmation_token: @token, redirect_url: @redirect_url} + end + + test "yield resource to block on show success" do + assert @controller.show_block_called?, "show failed to yield resource to provided block" + end + + end + +end diff --git a/test/controllers/custom/custom_omniauth_callbacks_controller_test.rb b/test/controllers/custom/custom_omniauth_callbacks_controller_test.rb new file mode 100644 index 000000000..a5b8fea95 --- /dev/null +++ b/test/controllers/custom/custom_omniauth_callbacks_controller_test.rb @@ -0,0 +1,30 @@ +require 'test_helper' + +class Custom::OmniauthCallbacksControllerTest < ActionDispatch::IntegrationTest + + describe Custom::OmniauthCallbacksController do + + setup do + OmniAuth.config.test_mode = true + OmniAuth.config.mock_auth[:facebook] = OmniAuth::AuthHash.new({ + :provider => 'facebook', + :uid => '123545', + :info => { + name: 'swong', + email: 'swongsong@yandex.ru' + } + }) + end + + test "yield resource to block on omniauth_success success" do + @redirect_url = "http://ng-token-auth.dev/" + get_via_redirect '/nice_user_auth/facebook', { + auth_origin_url: @redirect_url, + omniauth_window_type: 'newWindow' + } + assert @controller.omniauth_success_block_called?, "omniauth_success failed to yield resource to provided block" + end + + end + +end diff --git a/test/controllers/custom/custom_passwords_controller_test.rb b/test/controllers/custom/custom_passwords_controller_test.rb new file mode 100644 index 000000000..4da315769 --- /dev/null +++ b/test/controllers/custom/custom_passwords_controller_test.rb @@ -0,0 +1,81 @@ +require 'test_helper' + +class Custom::PasswordsControllerTest < ActionController::TestCase + + describe Custom::PasswordsController do + + before do + @resource = users(:confirmed_email_user) + @redirect_url = 'http://ng-token-auth.dev' + end + + test "yield resource to block on create success" do + post :create, { + email: @resource.email, + redirect_url: @redirect_url + } + + @mail = ActionMailer::Base.deliveries.last + @resource.reload + + @mail_config_name = CGI.unescape(@mail.body.match(/config=([^&]*)&/)[1]) + @mail_redirect_url = CGI.unescape(@mail.body.match(/redirect_url=([^&]*)&/)[1]) + @mail_reset_token = @mail.body.match(/reset_password_token=(.*)\"/)[1] + + assert @controller.create_block_called?, "create failed to yield resource to provided block" + end + + test "yield resource to block on edit success" do + @resource = users(:unconfirmed_email_user) + @redirect_url = 'http://ng-token-auth.dev' + + xhr :post, :create, { + email: @resource.email, + redirect_url: @redirect_url + } + + @mail = ActionMailer::Base.deliveries.last + @resource.reload + + @mail_config_name = CGI.unescape(@mail.body.match(/config=([^&]*)&/)[1]) + @mail_redirect_url = CGI.unescape(@mail.body.match(/redirect_url=([^&]*)&/)[1]) + @mail_reset_token = @mail.body.match(/reset_password_token=(.*)\"/)[1] + + xhr :get, :edit, { + reset_password_token: @mail_reset_token, + redirect_url: @mail_redirect_url + } + + @resource.reload + assert @controller.edit_block_called?, "edit failed to yield resource to provided block" + end + + test "yield resource to block on update success" do + @auth_headers = @resource.create_new_auth_token + request.headers.merge!(@auth_headers) + @new_password = Faker::Internet.password + put :update, { + password: @new_password, + password_confirmation: @new_password + } + assert @controller.update_block_called?, "update failed to yield resource to provided block" + end + + test "yield resource to block on update success with custom json" do + @auth_headers = @resource.create_new_auth_token + request.headers.merge!(@auth_headers) + @new_password = Faker::Internet.password + put :update, { + password: @new_password, + password_confirmation: @new_password + } + + @data = JSON.parse(response.body) + + assert @controller.update_block_called?, "update failed to yield resource to provided block" + assert_equal @data["custom"], "foo" + end + + end + +end diff --git a/test/controllers/custom/custom_registrations_controller_test.rb b/test/controllers/custom/custom_registrations_controller_test.rb new file mode 100644 index 000000000..0a1d411c8 --- /dev/null +++ b/test/controllers/custom/custom_registrations_controller_test.rb @@ -0,0 +1,52 @@ +require 'test_helper' + +class Custom::RegistrationsControllerTest < ActionDispatch::IntegrationTest + + describe Custom::RegistrationsController do + + setup do + @create_params = { + email: Faker::Internet.email, + password: "secret123", + password_confirmation: "secret123", + confirm_success_url: Faker::Internet.url, + unpermitted_param: '(x_x)' + } + + @existing_user = nice_users(:confirmed_email_user) + @auth_headers = @existing_user.create_new_auth_token + @client_id = @auth_headers['client'] + + # ensure request is not treated as batch request + age_token(@existing_user, @client_id) + end + + test "yield resource to block on create success" do + post '/nice_user_auth', @create_params + assert @controller.create_block_called?, "create failed to yield resource to provided block" + end + + test "yield resource to block on create success with custom json" do + post '/nice_user_auth', @create_params + + @data = JSON.parse(response.body) + + assert @controller.create_block_called?, "create failed to yield resource to provided block" + assert_equal @data["custom"], "foo" + end + + test "yield resource to block on update success" do + put '/nice_user_auth', { + nickname: "Ol' Sunshine-face", + }, @auth_headers + assert @controller.update_block_called?, "update failed to yield resource to provided block" + end + + test "yield resource to block on destroy success" do + delete '/nice_user_auth', @auth_headers + assert @controller.destroy_block_called?, "destroy failed to yield resource to provided block" + end + + end + +end diff --git a/test/controllers/custom/custom_sessions_controller_test.rb b/test/controllers/custom/custom_sessions_controller_test.rb new file mode 100644 index 000000000..2f9431e1b --- /dev/null +++ b/test/controllers/custom/custom_sessions_controller_test.rb @@ -0,0 +1,39 @@ +require 'test_helper' + +class Custom::SessionsControllerTest < ActionController::TestCase + + describe Custom::SessionsController do + + before do + @existing_user = users(:confirmed_email_user) + @existing_user.skip_confirmation! + @existing_user.save! + end + + test "yield resource to block on create success" do + post :create, { + email: @existing_user.email, + password: 'secret123' + } + assert @controller.create_block_called?, "create failed to yield resource to provided block" + end + + test "yield resource to block on destroy success" do + @auth_headers = @existing_user.create_new_auth_token + request.headers.merge!(@auth_headers) + delete :destroy, format: :json + assert @controller.destroy_block_called?, "destroy failed to yield resource to provided block" + end + + test "render method override" do + post :create, { + email: @existing_user.email, + password: 'secret123' + } + @data = JSON.parse(response.body) + assert_equal @data["custom"], "foo" + end + + end + +end diff --git a/test/controllers/custom/custom_token_validations_controller_test.rb b/test/controllers/custom/custom_token_validations_controller_test.rb new file mode 100644 index 000000000..a515d561f --- /dev/null +++ b/test/controllers/custom/custom_token_validations_controller_test.rb @@ -0,0 +1,38 @@ +require 'test_helper' + +class Custom::TokenValidationsControllerTest < ActionDispatch::IntegrationTest + + describe Custom::TokenValidationsController do + + before do + @resource = nice_users(:confirmed_email_user) + @resource.skip_confirmation! + @resource.save! + + @auth_headers = @resource.create_new_auth_token + + @token = @auth_headers['access-token'] + @client_id = @auth_headers['client'] + @expiry = @auth_headers['expiry'] + + # ensure that request is not treated as batch request + age_token(@resource, @client_id) + end + + test "yield resource to block on validate_token success" do + get '/nice_user_auth/validate_token', {}, @auth_headers + assert @controller.validate_token_block_called?, "validate_token failed to yield resource to provided block" + end + + test "yield resource to block on validate_token success with custom json" do + get '/nice_user_auth/validate_token', {}, @auth_headers + + @data = JSON.parse(response.body) + + assert @controller.validate_token_block_called?, "validate_token failed to yield resource to provided block" + assert_equal @data["custom"], "foo" + end + + end + +end diff --git a/test/controllers/demo_group_controller_test.rb b/test/controllers/demo_group_controller_test.rb index 2e9922fcf..813f90378 100644 --- a/test/controllers/demo_group_controller_test.rb +++ b/test/controllers/demo_group_controller_test.rb @@ -120,7 +120,20 @@ class DemoGroupControllerTest < ActionDispatch::IntegrationTest end end end + + describe 'failed access' do + before do + get '/demo/members_only_group', {}, @mang_auth_headers.merge({'access-token' => "bogus"}) + end + + it 'should not return any auth headers' do + refute response.headers['access-token'] + end + + it 'should return error: unauthorized status' do + assert_equal 401, response.status + end + end end end end - diff --git a/test/controllers/demo_user_controller_test.rb b/test/controllers/demo_user_controller_test.rb index 81720de3f..226bd972f 100644 --- a/test/controllers/demo_user_controller_test.rb +++ b/test/controllers/demo_user_controller_test.rb @@ -7,6 +7,7 @@ # was the appropriate message delivered in the json payload? class DemoUserControllerTest < ActionDispatch::IntegrationTest + include Warden::Test::Helpers describe DemoUserController do describe "Token access" do before do @@ -200,6 +201,31 @@ class DemoUserControllerTest < ActionDispatch::IntegrationTest end end + describe 'unbatch' do + before do + @resource.reload + age_token(@resource, @client_id) + + get '/demo/members_only', {}, @auth_headers + + @first_is_batch_request = assigns(:is_batch_request) + @first_user = assigns(:resource).dup + @first_access_token = response.headers['access-token'] + @first_response_status = response.status + + get '/demo/members_only?unbatch=true', {}, @auth_headers + + @second_is_batch_request = assigns(:is_batch_request) + @second_user = assigns(:resource) + @second_access_token = response.headers['access-token'] + @second_response_status = response.status + end + + it 'should NOT treat the second request as a batch request when "unbatch" param is set' do + refute @second_is_batch_request + end + end + describe 'time out' do before do @resource.reload @@ -257,6 +283,231 @@ class DemoUserControllerTest < ActionDispatch::IntegrationTest end end end + + describe 'successful password change' do + before do + DeviseTokenAuth.remove_tokens_after_password_reset = true + + # adding one more token to simulate another logged in device + @old_auth_headers = @auth_headers + @auth_headers = @resource.create_new_auth_token + age_token(@resource, @client_id) + assert @resource.tokens.count > 1 + + # password changed from new device + @resource.update_attributes({ + password: 'newsecret123', + password_confirmation: 'newsecret123' + }) + + get '/demo/members_only', {}, @auth_headers + end + + after do + DeviseTokenAuth.remove_tokens_after_password_reset = false + end + + it 'should have only one token' do + assert_equal 1, @resource.tokens.count + end + + it 'new request should be successful' do + assert 200, response.status + end + + describe 'another device should not be able to login' do + + it 'should return forbidden status' do + get '/demo/members_only', {}, @old_auth_headers + assert 401, response.status + end + + end + + end + + describe 'request including destroy of token' do + describe 'when change_headers_on_each_request is set to false' do + before do + DeviseTokenAuth.change_headers_on_each_request = false + age_token(@resource, @client_id) + + get '/demo/members_only_remove_token', {}, @auth_headers + end + + after do + DeviseTokenAuth.change_headers_on_each_request = true + end + + it 'should not return auth-headers' do + refute response.headers['access-token'] + end + end + + describe 'when change_headers_on_each_request is set to true' do + before do + age_token(@resource, @client_id) + get '/demo/members_only_remove_token', {}, @auth_headers + end + + it 'should not return auth-headers' do + refute response.headers['access-token'] + end + end + end + + describe 'when access-token name has been changed' do + before do + # ensure that request is not treated as batch request + DeviseTokenAuth.headers_names[:'access-token'] = 'new-access-token' + auth_headers_modified = @resource.create_new_auth_token + client_id = auth_headers_modified['client'] + age_token(@resource, client_id) + + get '/demo/members_only', {}, auth_headers_modified + @resp_token = response.headers['new-access-token'] + end + + it 'should have "new-access-token" header' do + assert @resp_token.present? + end + + after do + DeviseTokenAuth.headers_names[:'access-token'] = 'access-token' + end + end + end + + describe 'enable_standard_devise_support' do + + before do + @resource = users(:confirmed_email_user) + @auth_headers = @resource.create_new_auth_token + DeviseTokenAuth.enable_standard_devise_support = true + end + + describe 'Existing Warden authentication' do + before do + @resource = users(:second_confirmed_email_user) + @resource.skip_confirmation! + @resource.save! + login_as( @resource, :scope => :user) + + # no auth headers sent, testing that warden authenticates correctly. + get '/demo/members_only', {}, nil + + @resp_token = response.headers['access-token'] + @resp_client_id = response.headers['client'] + @resp_expiry = response.headers['expiry'] + @resp_uid = response.headers['uid'] + end + + describe 'devise mappings' do + it 'should define current_user' do + assert_equal @resource, @controller.current_user + end + + it 'should define user_signed_in?' do + assert @controller.user_signed_in? + end + + it 'should not define current_mang' do + refute_equal @resource, @controller.current_mang + end + + + it 'should increase the number of tokens by a factor of 2 up to 11' do + @first_token = @resource.tokens.keys.first + + DeviseTokenAuth.max_number_of_devices = 11 + (1..10).each do |n| + assert_equal [11, 2*n].min, @resource.reload.tokens.keys.length + get '/demo/members_only', {}, nil + end + + assert_not_includes @resource.reload.tokens.keys, @first_token + end + end + + it 'should return success status' do + assert_equal 200, response.status + end + + it 'should receive new token after successful request' do + assert @resp_token + end + + it 'should set the token expiry in the auth header' do + assert @resp_expiry + end + + it 'should return the client id in the auth header' do + assert @resp_client_id + end + + it "should return the user's uid in the auth header" do + assert @resp_uid + end + end + + describe 'existing Warden authentication with ignored token data' do + before do + @resource = users(:second_confirmed_email_user) + @resource.skip_confirmation! + @resource.save! + login_as( @resource, :scope => :user) + + get '/demo/members_only', {}, @auth_headers + + @resp_token = response.headers['access-token'] + @resp_client_id = response.headers['client'] + @resp_expiry = response.headers['expiry'] + @resp_uid = response.headers['uid'] + end + + describe 'devise mappings' do + it 'should define current_user' do + assert_equal @resource, @controller.current_user + end + + it 'should define user_signed_in?' do + assert @controller.user_signed_in? + end + + it 'should not define current_mang' do + refute_equal @resource, @controller.current_mang + end + end + + it 'should return success status' do + assert_equal 200, response.status + end + + it 'should receive new token after successful request' do + assert @resp_token + end + + it 'should set the token expiry in the auth header' do + assert @resp_expiry + end + + it 'should return the client id in the auth header' do + assert @resp_client_id + end + + it "should not use the existing token's client" do + refute_equal @auth_headers['client'], @resp_client_id + end + + it "should return the user's uid in the auth header" do + assert @resp_uid + end + + it "should not return the token user's uid in the auth header" do + refute_equal @resp_uid, @auth_headers['uid'] + end + end + end end end diff --git a/test/controllers/devise_token_auth/confirmations_controller_test.rb b/test/controllers/devise_token_auth/confirmations_controller_test.rb index 6268408f4..19069b082 100644 --- a/test/controllers/devise_token_auth/confirmations_controller_test.rb +++ b/test/controllers/devise_token_auth/confirmations_controller_test.rb @@ -8,6 +8,12 @@ class DeviseTokenAuth::ConfirmationsControllerTest < ActionController::TestCase describe DeviseTokenAuth::ConfirmationsController do + def token_and_client_config_from(body) + token = body.match(/confirmation_token=([^&]*)&/)[1] + client_config = body.match(/config=([^&]*)&/)[1] + [token, client_config] + end + describe "Confirmation" do before do @redirect_url = Faker::Internet.url @@ -15,9 +21,8 @@ class DeviseTokenAuth::ConfirmationsControllerTest < ActionController::TestCase @new_user.send_confirmation_instructions({ redirect_url: @redirect_url }) - @mail = ActionMailer::Base.deliveries.last - @token = @mail.body.match(/confirmation_token=([^&]*)&/)[1] - @client_config = @mail.body.match(/config=([^&]*)&/)[1] + mail = ActionMailer::Base.deliveries.last + @token, @client_config = token_and_client_config_from(mail.body) end test 'should generate raw token' do @@ -74,9 +79,8 @@ class DeviseTokenAuth::ConfirmationsControllerTest < ActionController::TestCase @new_user.send_confirmation_instructions(client_config: @config_name) - @mail = ActionMailer::Base.deliveries.last - @token = @mail.body.match(/confirmation_token=(.*)\"/)[1] - @client_config = @mail.body.match(/config=(.*)\&/)[1] + mail = ActionMailer::Base.deliveries.last + @token, @client_config = token_and_client_config_from(mail.body) end test 'should generate raw token' do diff --git a/test/controllers/devise_token_auth/omniauth_callbacks_controller_test.rb b/test/controllers/devise_token_auth/omniauth_callbacks_controller_test.rb index 2c0cdec06..34d02a9f3 100644 --- a/test/controllers/devise_token_auth/omniauth_callbacks_controller_test.rb +++ b/test/controllers/devise_token_auth/omniauth_callbacks_controller_test.rb @@ -1,4 +1,5 @@ require 'test_helper' +require 'mocha/test_unit' # was the web request successful? # was the user redirected to the right page? @@ -9,96 +10,95 @@ class OmniauthTest < ActionDispatch::IntegrationTest setup do OmniAuth.config.test_mode = true - OmniAuth.config.mock_auth[:facebook] = OmniAuth::AuthHash.new({ - :provider => 'facebook', - :uid => '123545', - :info => { - name: 'chong', - email: 'chongbong@aol.com' - } - }) end before do @redirect_url = "http://ng-token-auth.dev/" end - describe 'default user model' do - describe 'from api to provider' do - before do - get_via_redirect '/auth/facebook', { - auth_origin_url: @redirect_url + describe 'success callback' do + setup do + OmniAuth.config.mock_auth[:facebook] = OmniAuth::AuthHash.new({ + :provider => 'facebook', + :uid => '123545', + :info => { + name: 'chong', + email: 'chongbong@aol.com' } + }) + end - @resource = assigns(:resource) - end + test 'request should pass correct redirect_url' do + get_success + assert_equal @redirect_url, controller.send(:omniauth_params)['auth_origin_url'] + end - test 'status should be success' do - assert_equal 200, response.status - end + test 'user should have been created' do + get_success + assert @resource + end - test 'request should determine the correct resource_class' do - assert_equal 'User', controller.omniauth_params['resource_class'] - end + test 'user should be assigned info from provider' do + get_success + assert_equal 'chongbong@aol.com', @resource.email + end - test 'request should pass correct redirect_url' do - assert_equal @redirect_url, controller.omniauth_params['auth_origin_url'] - end + test 'user should be assigned token' do + get_success + client_id = controller.auth_params[:client_id] + token = controller.auth_params[:auth_token] + expiry = controller.auth_params[:expiry] - test 'user should have been created' do - assert @resource - end + # the expiry should have been set + assert_equal expiry, @resource.tokens[client_id][:expiry] + # the token sent down to the client should now be valid + assert @resource.valid_token?(token, client_id) + end + + test 'session vars have been cleared' do + get_success + refute request.session['dta.omniauth.auth'] + refute request.session['dta.omniauth.params'] + end + + test 'sign_in was called' do + User.any_instance.expects(:sign_in) + get_success + end + + test 'should be redirected via valid url' do + get_success + assert_equal 'http://www.example.com/auth/facebook/callback', request.original_url + end - test 'user should be assigned info from provider' do - assert_equal 'chongbong@aol.com', @resource.email + describe 'with default user model' do + before do + get_success + end + test 'request should determine the correct resource_class' do + assert_equal 'User', controller.send(:omniauth_params)['resource_class'] end test 'user should be of the correct class' do assert_equal User, @resource.class end + end - test 'response contains all serializable attributes for user' do - post_message = JSON.parse(/postMessage\((?.*), '\*'\);/m.match(response.body)[:data]) - - assert post_message["id"] - assert post_message["email"] - assert post_message["uid"] - assert post_message["name"] - assert post_message["favorite_color"] - assert post_message["message"] - assert post_message["client_id"] - assert post_message["auth_token"] - refute post_message["tokens"] - refute post_message["password"] + describe 'with alternate user model' do + before do + get_via_redirect '/mangs/facebook', { + auth_origin_url: @redirect_url, + omniauth_window_type: 'newWindow' + } + assert_equal 200, response.status + @resource = assigns(:resource) end - - test 'session vars have been cleared' do - refute request.session['dta.omniauth.auth'] - refute request.session['dta.omniauth.params'] + test 'request should determine the correct resource_class' do + assert_equal 'Mang', controller.send(:omniauth_params)['resource_class'] end - - describe 'trackable' do - test 'sign_in_count incrementns' do - assert @resource.sign_in_count > 0 - end - - test 'current_sign_in_at is updated' do - assert @resource.current_sign_in_at - end - - test 'last_sign_in_at is updated' do - assert @resource.last_sign_in_at - end - - test 'sign_in_ip is updated' do - assert @resource.current_sign_in_ip - end - - test 'last_sign_in_ip is updated' do - assert @resource.last_sign_in_ip - end + test 'user should be of the correct class' do + assert_equal Mang, @resource.class end - end describe 'pass additional params' do @@ -108,7 +108,8 @@ class OmniauthTest < ActionDispatch::IntegrationTest get_via_redirect '/auth/facebook', { auth_origin_url: @redirect_url, favorite_color: @fav_color, - name: @unpermitted_param + name: @unpermitted_param, + omniauth_window_type: 'newWindow' } @resource = assigns(:resource) @@ -126,42 +127,215 @@ class OmniauthTest < ActionDispatch::IntegrationTest refute_equal @unpermitted_param, @resource.name end end - end + describe "oauth registration attr" do + after do + User.any_instance.unstub(:new_record?) + end + + describe 'with new user' do + before do + User.any_instance.expects(:new_record?).returns(true).at_least_once + end + + test 'response contains oauth_registration attr' do + + get_via_redirect '/auth/facebook', { + auth_origin_url: @redirect_url, + omniauth_window_type: 'newWindow' + } + + assert_equal true, controller.auth_params[:oauth_registration] + end + end + + describe 'with existing user' do + before do + User.any_instance.expects(:new_record?).returns(false).at_least_once + end + + test 'response does not contain oauth_registration attr' do + + get_via_redirect '/auth/facebook', { + auth_origin_url: @redirect_url, + omniauth_window_type: 'newWindow' + } + + assert_equal false, controller.auth_params.key?(:oauth_registration) + end - describe 'alternate user model' do - describe 'from api to provider' do + end + + end + + describe 'using namespaces' do before do - get_via_redirect '/mangs/facebook', { - auth_origin_url: @redirect_url + get_via_redirect '/api/v1/auth/facebook', { + auth_origin_url: @redirect_url, + omniauth_window_type: 'newWindow' } @resource = assigns(:resource) end - test 'status should be success' do + test 'request is successful' do assert_equal 200, response.status end - test 'request should determine the correct resource_class' do - assert_equal 'Mang', controller.omniauth_params['resource_class'] + test 'user should have been created' do + assert @resource end - test 'request should pass correct redirect_url' do - assert_equal @redirect_url, controller.omniauth_params['auth_origin_url'] + test 'user should be of the correct class' do + assert_equal User, @resource.class end + end - test 'user should have been created' do - assert @resource + describe 'with omniauth_window_type=inAppBrowser' do + test 'response contains all expected data' do + get_success(omniauth_window_type: 'inAppBrowser') + assert_expected_data_in_new_window end - test 'user should be assigned info from provider' do - assert_equal 'chongbong@aol.com', @resource.email + end + + describe 'with omniauth_window_type=newWindow' do + test 'response contains all expected data' do + get_success(omniauth_window_type: 'newWindow') + assert_expected_data_in_new_window end + end - test 'user should be of the correct class' do - assert_equal Mang, @resource.class + def assert_expected_data_in_new_window + data_json = @response.body.match(/var data \= (.+)\;/)[1] + data = ActiveSupport::JSON.decode(data_json) + expected_data = @resource.as_json.merge(controller.auth_params.as_json) + expected_data = ActiveSupport::JSON.decode(expected_data.to_json) + assert_equal(expected_data.merge("message" => "deliverCredentials"), data) + end + + describe 'with omniauth_window_type=sameWindow' do + test 'redirects to auth_origin_url with all expected query params' do + get_via_redirect '/auth/facebook', { + auth_origin_url: '/auth_origin', + omniauth_window_type: 'sameWindow' + } + assert_equal 200, response.status + + # We have been forwarded to a url with all the expected + # data in the query params. + + # Assert that a uid was passed along. We have to assume + # that the rest of the values were as well, as we don't + # have access to @resource in this test anymore + assert(uid = controller.params['uid'], "No uid found") + + # check that all the auth stuff is there + [:auth_token, :client_id, :uid, :expiry, :config].each do |key| + assert(controller.params.key?(key), "No value for #{key.inspect}") + end end end + + def get_success(params = {}) + get_via_redirect '/auth/facebook', { + auth_origin_url: @redirect_url, + omniauth_window_type: 'newWindow' + }.merge(params) + assert_equal 200, response.status + @resource = assigns(:resource) + end + end + + describe 'failure callback' do + setup do + OmniAuth.config.mock_auth[:facebook] = :invalid_credentials + OmniAuth.config.on_failure = Proc.new { |env| + OmniAuth::FailureEndpoint.new(env).redirect_to_failure + } + end + + test 'renders expected data' do + get_via_redirect '/auth/facebook', { + auth_origin_url: @redirect_url, + omniauth_window_type: 'newWindow' + } + assert_equal 200, response.status + + data_json = @response.body.match(/var data \= (.+)\;/)[1] + data = ActiveSupport::JSON.decode(data_json) + + assert_equal({"error"=>"invalid_credentials", "message"=>"authFailure"}, data) + end + + test 'renders something with no auth_origin_url' do + get_via_redirect '/auth/facebook' + assert_equal 200, response.status + assert_select "body", "invalid_credentials" + end + end + + describe 'User with only :database_authenticatable and :registerable included' do + test 'OnlyEmailUser should not be able to use OAuth' do + assert_raises(ActionController::RoutingError) { + get_via_redirect '/only_email_auth/facebook', { + auth_origin_url: @redirect_url + } + } + end + end + + describe 'Using redirect_whitelist' do + before do + @user_email = 'slemp.diggler@sillybandz.gov' + OmniAuth.config.mock_auth[:facebook] = OmniAuth::AuthHash.new( + provider: 'facebook', + uid: '123545', + info: { + name: 'chong', + email: @user_email + } + ) + @good_redirect_url = Faker::Internet.url + @bad_redirect_url = Faker::Internet.url + DeviseTokenAuth.redirect_whitelist = [@good_redirect_url] + end + + teardown do + DeviseTokenAuth.redirect_whitelist = nil + end + + test 'request using non-whitelisted redirect fail' do + get_via_redirect '/auth/facebook', + auth_origin_url: @bad_redirect_url, + omniauth_window_type: 'newWindow' + + data_json = @response.body.match(/var data \= (.+)\;/)[1] + data = ActiveSupport::JSON.decode(data_json) + assert_equal "Redirect to '#{@bad_redirect_url}' not allowed.", + data['error'] + end + + test 'request to whitelisted redirect should succeed' do + get_via_redirect '/auth/facebook', + auth_origin_url: @good_redirect_url, + omniauth_window_type: 'newWindow' + + data_json = @response.body.match(/var data \= (.+)\;/)[1] + data = ActiveSupport::JSON.decode(data_json) + assert_equal @user_email, data['email'] + end + + test 'should support wildcards' do + DeviseTokenAuth.redirect_whitelist = ["#{@good_redirect_url[0..8]}*"] + get_via_redirect '/auth/facebook', + auth_origin_url: @good_redirect_url, + omniauth_window_type: 'newWindow' + + data_json = @response.body.match(/var data \= (.+)\;/)[1] + data = ActiveSupport::JSON.decode(data_json) + assert_equal @user_email, data['email'] + end + end end diff --git a/test/controllers/devise_token_auth/passwords_controller_test.rb b/test/controllers/devise_token_auth/passwords_controller_test.rb index dd02dca19..f3dc394d8 100644 --- a/test/controllers/devise_token_auth/passwords_controller_test.rb +++ b/test/controllers/devise_token_auth/passwords_controller_test.rb @@ -14,7 +14,80 @@ class DeviseTokenAuth::PasswordsControllerTest < ActionController::TestCase @redirect_url = 'http://ng-token-auth.dev' end + describe 'not email should return 401' do + before do + @auth_headers = @resource.create_new_auth_token + @new_password = Faker::Internet.password + + xhr :post, :create, { + redirect_url: @redirect_url + } + @data = JSON.parse(response.body) + end + + test 'response should fail' do + assert_equal 401, response.status + end + test 'error message should be returned' do + assert @data["errors"] + assert_equal @data["errors"], [I18n.t("devise_token_auth.passwords.missing_email")] + end + end + + describe 'not redirect_url should return 401' do + before do + @auth_headers = @resource.create_new_auth_token + @new_password = Faker::Internet.password + + xhr :post, :create, { + email: 'chester@cheet.ah', + } + @data = JSON.parse(response.body) + end + + test 'response should fail' do + assert_equal 401, response.status + end + test 'error message should be returned' do + assert @data["errors"] + assert_equal @data["errors"], [I18n.t("devise_token_auth.passwords.missing_redirect_url")] + end + end + describe 'request password reset' do + describe 'unknown user should return 404' do + before do + xhr :post, :create, { + email: 'chester@cheet.ah', + redirect_url: @redirect_url + } + @data = JSON.parse(response.body) + end + test 'unknown user should return 404' do + assert_equal 404, response.status + end + + test 'errors should be returned' do + assert @data["errors"] + assert_equal @data["errors"], [I18n.t("devise_token_auth.passwords.user_not_found", email: 'chester@cheet.ah')] + end + end + + describe 'successfully requested password reset' do + before do + xhr :post, :create, { + email: @resource.email, + redirect_url: @redirect_url + } + + @data = JSON.parse(response.body) + end + + test 'response should not contain extra data' do + assert_nil @data["data"] + end + end + describe 'case-sensitive email' do before do @@ -25,6 +98,7 @@ class DeviseTokenAuth::PasswordsControllerTest < ActionController::TestCase @mail = ActionMailer::Base.deliveries.last @resource.reload + @data = JSON.parse(response.body) @mail_config_name = CGI.unescape(@mail.body.match(/config=([^&]*)&/)[1]) @mail_redirect_url = CGI.unescape(@mail.body.match(/redirect_url=([^&]*)&/)[1]) @@ -35,6 +109,10 @@ class DeviseTokenAuth::PasswordsControllerTest < ActionController::TestCase assert_equal 200, response.status end + test 'response should contains message' do + assert_equal @data["message"], I18n.t("devise_token_auth.passwords.sended", email: @resource.email) + end + test 'action should send an email' do assert @mail end @@ -60,10 +138,10 @@ class DeviseTokenAuth::PasswordsControllerTest < ActionController::TestCase end describe 'password reset link failure' do - test 'request should not be authorized' do + test 'response should return 404' do assert_raises(ActionController::RoutingError) { xhr :get, :edit, { - reset_password_token: 'bogus', + reset_password_token: "bogus", redirect_url: @mail_redirect_url } } @@ -126,7 +204,172 @@ class DeviseTokenAuth::PasswordsControllerTest < ActionController::TestCase test 'response should return failure status if not configured' do @resource_class.case_insensitive_keys = [] xhr :post, :create, @request_params - assert_equal 400, response.status + assert_equal 404, response.status + end + end + end + + describe 'Using default_password_reset_url' do + before do + @resource = users(:confirmed_email_user) + @redirect_url = 'http://ng-token-auth.dev' + + DeviseTokenAuth.default_password_reset_url = @redirect_url + + xhr :post, :create, { + email: @resource.email, + redirect_url: @redirect_url + } + + @mail = ActionMailer::Base.deliveries.last + @resource.reload + + @sent_redirect_url = CGI.unescape(@mail.body.match(/redirect_url=([^&]*)&/)[1]) + end + + teardown do + DeviseTokenAuth.default_password_reset_url = nil + end + + test 'response should return success status' do + assert_equal 200, response.status + end + + test 'action should send an email' do + assert @mail + end + + test 'the email body should contain a link with redirect url as a query param' do + assert_equal @redirect_url, @sent_redirect_url + end + end + + describe 'Using redirect_whitelist' do + before do + @resource = users(:confirmed_email_user) + @good_redirect_url = Faker::Internet.url + @bad_redirect_url = Faker::Internet.url + DeviseTokenAuth.redirect_whitelist = [@good_redirect_url] + end + + teardown do + DeviseTokenAuth.redirect_whitelist = nil + end + + test "request to whitelisted redirect should be successful" do + xhr :post, :create, { + email: @resource.email, + redirect_url: @good_redirect_url + } + + assert_equal 200, response.status + end + + test "request to non-whitelisted redirect should fail" do + xhr :post, :create, { + email: @resource.email, + redirect_url: @bad_redirect_url + } + + assert_equal 422, response.status + end + test "request to non-whitelisted redirect should return error message" do + xhr :post, :create, { + email: @resource.email, + redirect_url: @bad_redirect_url + } + + @data = JSON.parse(response.body) + assert @data["errors"] + assert_equal @data["errors"], [I18n.t("devise_token_auth.passwords.not_allowed_redirect_url", redirect_url: @bad_redirect_url)] + end + end + + describe "change password with current password required" do + before do + DeviseTokenAuth.check_current_password_before_update = :password + end + + after do + DeviseTokenAuth.check_current_password_before_update = false + end + + describe 'success' do + before do + @auth_headers = @resource.create_new_auth_token + request.headers.merge!(@auth_headers) + @new_password = Faker::Internet.password + @resource.update password: 'secret123', password_confirmation: 'secret123' + + xhr :put, :update, { + password: @new_password, + password_confirmation: @new_password, + current_password: 'secret123' + } + + @data = JSON.parse(response.body) + @resource.reload + end + + test "request should be successful" do + assert_equal 200, response.status + end + end + + describe 'success with after password reset' do + before do + xhr :post, :create, { + email: @resource.email, + redirect_url: @redirect_url + } + + @mail = ActionMailer::Base.deliveries.last + @mail_redirect_url = CGI.unescape(@mail.body.match(/redirect_url=([^&]*)&/)[1]) + @mail_reset_token = @mail.body.match(/reset_password_token=(.*)\"/)[1] + + xhr :get, :edit, { + reset_password_token: @mail_reset_token, + redirect_url: @mail_redirect_url + } + + @auth_headers = @resource.create_new_auth_token + request.headers.merge!(@auth_headers) + @new_password = Faker::Internet.password + + xhr :put, :update, { + password: @new_password, + password_confirmation: @new_password + } + + @data = JSON.parse(response.body) + @allow_password_change = @resource.allow_password_change + @resource.reload + end + + test "request should be successful" do + assert_equal 200, response.status + end + + test "sets allow_password_change false" do + assert_equal false, @allow_password_change + end + end + + describe 'current password mismatch error' do + before do + @auth_headers = @resource.create_new_auth_token + request.headers.merge!(@auth_headers) + @new_password = Faker::Internet.password + + xhr :put, :update, { + password: @new_password, + password_confirmation: @new_password, + current_password: 'not_very_secret321' + } + end + + test 'response should fail unauthorized' do + assert_equal 422, response.status end end end @@ -143,6 +386,7 @@ class DeviseTokenAuth::PasswordsControllerTest < ActionController::TestCase password_confirmation: @new_password } + @data = JSON.parse(response.body) @resource.reload end @@ -150,6 +394,11 @@ class DeviseTokenAuth::PasswordsControllerTest < ActionController::TestCase assert_equal 200, response.status end + test "request should return success message" do + assert @data["message"] + assert_equal @data["message"], I18n.t("devise_token_auth.passwords.successfully_updated") + end + test "new password should authenticate user" do assert @resource.valid_password?(@new_password) end @@ -253,9 +502,38 @@ class DeviseTokenAuth::PasswordsControllerTest < ActionController::TestCase @resource.reload end + end + describe 'unconfirmable user' do + setup do + @request.env['devise.mapping'] = Devise.mappings[:unconfirmable_user] + end + + teardown do + @request.env['devise.mapping'] = Devise.mappings[:user] + end + + before do + @resource = unconfirmable_users(:user) + @redirect_url = 'http://ng-token-auth.dev' + + xhr :post, :create, { + email: @resource.email, + redirect_url: @redirect_url + } + + @mail = ActionMailer::Base.deliveries.last + @resource.reload - test 'unconfirmed email user should now be confirmed' do - assert @resource.confirmed_at + @mail_config_name = CGI.unescape(@mail.body.match(/config=([^&]*)&/)[1]) + @mail_redirect_url = CGI.unescape(@mail.body.match(/redirect_url=([^&]*)&/)[1]) + @mail_reset_token = @mail.body.match(/reset_password_token=(.*)\"/)[1] + + xhr :get, :edit, { + reset_password_token: @mail_reset_token, + redirect_url: @mail_redirect_url + } + + @resource.reload end end diff --git a/test/controllers/devise_token_auth/registrations_controller_test.rb b/test/controllers/devise_token_auth/registrations_controller_test.rb index 51370e7b8..e0df8bc9a 100644 --- a/test/controllers/devise_token_auth/registrations_controller_test.rb +++ b/test/controllers/devise_token_auth/registrations_controller_test.rb @@ -9,6 +9,32 @@ class DeviseTokenAuth::RegistrationsControllerTest < ActionDispatch::IntegrationTest describe DeviseTokenAuth::RegistrationsController do + describe 'Validate non-empty body' do + before do + # need to post empty data + post '/auth', {} + + @resource = assigns(:resource) + @data = JSON.parse(response.body) + end + + test 'request should fail' do + assert_equal 422, response.status + end + + test 'returns error message' do + assert_not_empty @data['errors'] + end + + test 'return error status' do + assert_equal 'error', @data['status'] + end + + test 'user should not have been saved' do + assert @resource.nil? + end + end + describe "Successful registration" do before do @mails_sent = ActionMailer::Base.deliveries.count @@ -55,6 +81,182 @@ class DeviseTokenAuth::RegistrationsControllerTest < ActionDispatch::Integration end end + describe 'using "+" in email' do + test 'can use + sign in email addresses' do + @plus_email = 'ak+testing@gmail.com' + + post '/auth', { + email: @plus_email, + password: "secret123", + password_confirmation: "secret123", + confirm_success_url: Faker::Internet.url + } + + @resource = assigns(:resource) + + assert_equal @plus_email, @resource.email + end + end + + describe 'Using redirect_whitelist' do + before do + @good_redirect_url = Faker::Internet.url + @bad_redirect_url = Faker::Internet.url + DeviseTokenAuth.redirect_whitelist = [@good_redirect_url] + end + + teardown do + DeviseTokenAuth.redirect_whitelist = nil + end + + test "request to whitelisted redirect should be successful" do + post '/auth', { + email: Faker::Internet.email, + password: "secret123", + password_confirmation: "secret123", + confirm_success_url: @good_redirect_url, + unpermitted_param: '(x_x)' + } + + assert_equal 200, response.status + end + + test "request to non-whitelisted redirect should fail" do + post '/auth', { + email: Faker::Internet.email, + password: "secret123", + password_confirmation: "secret123", + confirm_success_url: @bad_redirect_url, + unpermitted_param: '(x_x)' + } + @data = JSON.parse(response.body) + + assert_equal 422, response.status + assert @data["errors"] + assert_equal @data["errors"], [I18n.t("devise_token_auth.registrations.redirect_url_not_allowed", redirect_url: @bad_redirect_url)] + end + end + + describe 'failure if not redirecturl' do + + test "request should fail if not redirect_url" do + post '/auth', { + email: Faker::Internet.email, + password: "secret123", + password_confirmation: "secret123", + unpermitted_param: '(x_x)' + } + + assert_equal 422, response.status + end + + test "request to non-whitelisted redirect should fail" do + post '/auth', { + email: Faker::Internet.email, + password: "secret123", + password_confirmation: "secret123", + unpermitted_param: '(x_x)' + } + @data = JSON.parse(response.body) + + assert @data["errors"] + assert_equal @data["errors"], [I18n.t("devise_token_auth.registrations.missing_confirm_success_url")] + end + end + + describe 'Using default_confirm_success_url' do + before do + @mails_sent = ActionMailer::Base.deliveries.count + @redirect_url = Faker::Internet.url + + DeviseTokenAuth.default_confirm_success_url = @redirect_url + + post '/auth', { + email: Faker::Internet.email, + password: "secret123", + password_confirmation: "secret123", + unpermitted_param: '(x_x)' + } + + @resource = assigns(:resource) + @data = JSON.parse(response.body) + @mail = ActionMailer::Base.deliveries.last + @sent_redirect_url = URI.decode(@mail.body.match(/redirect_url=([^&]*)(&|\")/)[1]) + end + + teardown do + DeviseTokenAuth.default_confirm_success_url = nil + end + + test "request should be successful" do + assert_equal 200, response.status + end + + test "the email was sent" do + assert_equal @mails_sent + 1, ActionMailer::Base.deliveries.count + end + + test 'email contains the default redirect url' do + assert_equal @redirect_url, @sent_redirect_url + end + end + + describe 'using namespaces' do + before do + @mails_sent = ActionMailer::Base.deliveries.count + + post '/api/v1/auth', { + email: Faker::Internet.email, + password: "secret123", + password_confirmation: "secret123", + confirm_success_url: Faker::Internet.url, + unpermitted_param: '(x_x)' + } + + @resource = assigns(:resource) + @data = JSON.parse(response.body) + @mail = ActionMailer::Base.deliveries.last + end + + test "request should be successful" do + assert_equal 200, response.status + end + + test "user should have been created" do + assert @resource.id + end + end + + describe "case-insensitive email" do + + before do + @resource_class = User + @request_params = { + email: "AlternatingCase@example.com", + password: "secret123", + password_confirmation: "secret123", + confirm_success_url: Faker::Internet.url + } + end + + test "success should downcase uid if configured" do + @resource_class.case_insensitive_keys = [:email] + post '/auth', @request_params + assert_equal 200, response.status + @data = JSON.parse(response.body) + assert_equal "alternatingcase@example.com", @data['data']['uid'] + end + + test "request should not downcase uid if not configured" do + @resource_class.case_insensitive_keys = [] + post '/auth', @request_params + assert_equal 200, response.status + @data = JSON.parse(response.body) + assert_equal "AlternatingCase@example.com", @data['data']['uid'] + end + + end + describe "Adding extra params" do before do @redirect_url = Faker::Internet.url @@ -95,6 +297,65 @@ class DeviseTokenAuth::RegistrationsControllerTest < ActionDispatch::Integration end end + describe 'bad email' do + before do + post '/auth', { + email: "false_email@", + password: "secret123", + password_confirmation: "secret123", + confirm_success_url: Faker::Internet.url + } + + @resource = assigns(:resource) + @data = JSON.parse(response.body) + end + + test "request should not be successful" do + assert_equal 422, response.status + end + + test "user should not have been created" do + assert_nil @resource.id + end + + test "error should be returned in the response" do + assert @data['errors'].length + end + + test "full_messages should be included in error hash" do + assert @data['errors']['full_messages'].length + end + end + + describe 'missing email' do + before do + post '/auth', { + password: "secret123", + password_confirmation: "secret123", + confirm_success_url: Faker::Internet.url + } + + @resource = assigns(:resource) + @data = JSON.parse(response.body) + end + + test "request should not be successful" do + assert_equal 422, response.status + end + + test "user should not have been created" do + assert_nil @resource.id + end + + test "error should be returned in the response" do + assert @data['errors'].length + end + + test "full_messages should be included in error hash" do + assert @data['errors']['full_messages'].length + end + end + describe "Mismatched passwords" do before do post '/auth', { @@ -109,7 +370,7 @@ class DeviseTokenAuth::RegistrationsControllerTest < ActionDispatch::Integration end test "request should not be successful" do - assert_equal 403, response.status + assert_equal 422, response.status end test "user should have been created" do @@ -141,7 +402,7 @@ class DeviseTokenAuth::RegistrationsControllerTest < ActionDispatch::Integration end test "request should not be successful" do - assert_equal 403, response.status + assert_equal 422, response.status end test "user should have been created" do @@ -173,6 +434,10 @@ class DeviseTokenAuth::RegistrationsControllerTest < ActionDispatch::Integration assert_equal 200, response.status end + test "message should be returned" do + assert @data["message"] + assert_equal @data["message"], I18n.t("devise_token_auth.registrations.account_with_uid_destroyed", uid: @existing_user.uid) + end test "existing user should be deleted" do refute User.where(id: @existing_user.id).first end @@ -187,6 +452,11 @@ class DeviseTokenAuth::RegistrationsControllerTest < ActionDispatch::Integration test 'request returns 404 (not found) status' do assert_equal 404, response.status end + + test 'error should be returned' do + assert @data['errors'].length + assert_equal @data['errors'], [I18n.t("devise_token_auth.registrations.account_to_destroy_not_found")] + end end end @@ -202,46 +472,207 @@ class DeviseTokenAuth::RegistrationsControllerTest < ActionDispatch::Integration age_token(@existing_user, @client_id) end - describe "success" do + describe "without password check" do + describe "success" do + before do + # test valid update param + @resource_class = User + @new_operating_thetan = 1000000 + @email = "AlternatingCase2@example.com" + @request_params = { + operating_thetan: @new_operating_thetan, + email: @email + } + end + + test "Request was successful" do + put "/auth", @request_params, @auth_headers + assert_equal 200, response.status + end + + test "Case sensitive attributes update" do + @resource_class.case_insensitive_keys = [] + put "/auth", @request_params, @auth_headers + @data = JSON.parse(response.body) + @existing_user.reload + assert_equal @new_operating_thetan, @existing_user.operating_thetan + assert_equal @email, @existing_user.email + assert_equal @email, @existing_user.uid + end + + test "Case insensitive attributes update" do + @resource_class.case_insensitive_keys = [:email] + put "/auth", @request_params, @auth_headers + @data = JSON.parse(response.body) + @existing_user.reload + assert_equal @new_operating_thetan, @existing_user.operating_thetan + assert_equal @email.downcase, @existing_user.email + assert_equal @email.downcase, @existing_user.uid + end + + test "Supply current password" do + @request_params.merge!( + current_password: "secret123", + email: "new.email@example.com", + ) + + put "/auth", @request_params, @auth_headers + @data = JSON.parse(response.body) + @existing_user.reload + assert_equal @existing_user.email, "new.email@example.com" + end + end + + describe 'validate non-empty body' do + before do + # get the email so we can check it wasn't updated + @email = @existing_user.email + put '/auth', {}, @auth_headers + + @data = JSON.parse(response.body) + @existing_user.reload + end + + test 'request should fail' do + assert_equal 422, response.status + end + + test 'returns error message' do + assert_not_empty @data['errors'] + end + + test 'return error status' do + assert_equal 'error', @data['status'] + end + + test 'user should not have been saved' do + assert_equal @email, @existing_user.email + end + end + + describe "error" do + before do + # test invalid update param + @new_operating_thetan = "blegh" + put "/auth", { + operating_thetan: @new_operating_thetan + }, @auth_headers + + @data = JSON.parse(response.body) + @existing_user.reload + end + + test "Request was NOT successful" do + assert_equal 422, response.status + end + + test "Errors were provided with response" do + assert @data["errors"].length + end + end + end + + describe "with password check for password update only" do before do - # test valid update param - @new_operating_thetan = 1000000 + DeviseTokenAuth.check_current_password_before_update = :password + end - put "/auth", { - operating_thetan: @new_operating_thetan - }, @auth_headers + after do + DeviseTokenAuth.check_current_password_before_update = false + end - @data = JSON.parse(response.body) - @existing_user.reload + describe "success without password update" do + before do + # test valid update param + @resource_class = User + @new_operating_thetan = 1000000 + @email = "AlternatingCase2@example.com" + @request_params = { + operating_thetan: @new_operating_thetan, + email: @email + } + end + + test "Request was successful" do + put "/auth", @request_params, @auth_headers + assert_equal 200, response.status + end end - test "Request was successful" do - assert_equal 200, response.status + describe "success with password update" do + before do + @existing_user.update password: 'secret123', password_confirmation: 'secret123' + @request_params = { + password: 'the_new_secret456', + password_confirmation: 'the_new_secret456', + current_password: 'secret123' + } + end + + test "Request was successful" do + put "/auth", @request_params, @auth_headers + assert_equal 200, response.status + end end - test "User attribute was updated" do - assert_equal @new_operating_thetan, @existing_user.operating_thetan + describe "error with password mismatch" do + before do + @existing_user.update password: 'secret123', password_confirmation: 'secret123' + @request_params = { + password: 'the_new_secret456', + password_confirmation: 'the_new_secret456', + current_password: 'not_so_secret321' + } + end + + test "Request was NOT successful" do + put "/auth", @request_params, @auth_headers + assert_equal 422, response.status + end end end - describe "error" do + describe "with password check for all attributes" do before do - # test invalid update param - @new_operating_thetan = "blegh" - put "/auth", { - operating_thetan: @new_operating_thetan - }, @auth_headers - - @data = JSON.parse(response.body) - @existing_user.reload + DeviseTokenAuth.check_current_password_before_update = :password + @new_operating_thetan = 1000000 + @email = "AlternatingCase2@example.com" + end + + after do + DeviseTokenAuth.check_current_password_before_update = false end - test "Request was NOT successful" do - assert_equal 403, response.status + describe "success with password update" do + before do + @existing_user.update password: 'secret123', password_confirmation: 'secret123' + @request_params = { + operating_thetan: @new_operating_thetan, + email: @email, + current_password: 'secret123' + } + end + + test "Request was successful" do + put "/auth", @request_params, @auth_headers + assert_equal 200, response.status + end end - test "Errors were provided with response" do - assert @data["errors"].length + describe "error with password mismatch" do + before do + @existing_user.update password: 'secret123', password_confirmation: 'secret123' + @request_params = { + operating_thetan: @new_operating_thetan, + email: @email, + current_password: 'not_so_secret321' + } + end + + test "Request was NOT successful" do + put "/auth", @request_params, @auth_headers + assert_equal 422, response.status + end end end end @@ -270,6 +701,11 @@ class DeviseTokenAuth::RegistrationsControllerTest < ActionDispatch::Integration assert_equal 404, response.status end + test "error should be returned" do + assert @data["errors"].length + assert_equal @data["errors"], [I18n.t("devise_token_auth.registrations.user_not_found")] + end + test "User should not be updated" do refute_equal @new_operating_thetan, @existing_user.operating_thetan end @@ -327,13 +763,15 @@ class DeviseTokenAuth::RegistrationsControllerTest < ActionDispatch::Integration end test "Mang should be destroyed" do + @resource.skip_confirmation! + @resource.save! @auth_headers = @resource.create_new_auth_token @client_id = @auth_headers['client'] # ensure request is not treated as batch request age_token(@resource, @client_id) - delete "/mangs", {}, @auth_headers + xhr :delete, "/mangs", {}, @auth_headers assert_equal 200, response.status refute Mang.where(id: @resource.id).first @@ -368,6 +806,19 @@ class DeviseTokenAuth::RegistrationsControllerTest < ActionDispatch::Integration end end + describe 'Excluded :registrations module' do + test 'UnregisterableUser should not be able to access registration routes' do + assert_raises(ActionController::RoutingError) { + post '/unregisterable_user_auth', { + email: Faker::Internet.email, + password: "secret123", + password_confirmation: "secret123", + confirm_success_url: Faker::Internet.url + } + } + end + end + describe "Skipped confirmation" do setup do User.set_callback(:create, :before, :skip_confirmation!) @@ -408,5 +859,36 @@ class DeviseTokenAuth::RegistrationsControllerTest < ActionDispatch::Integration assert @resource.valid_token?(@token, @client_id) end end + + + describe 'User with only :database_authenticatable and :registerable included' do + setup do + @mails_sent = ActionMailer::Base.deliveries.count + + post '/only_email_auth', { + email: Faker::Internet.email, + password: "secret123", + password_confirmation: "secret123", + confirm_success_url: Faker::Internet.url, + unpermitted_param: '(x_x)' + } + + @resource = assigns(:resource) + @data = JSON.parse(response.body) + @mail = ActionMailer::Base.deliveries.last + end + + test 'user was created' do + assert @resource.id + end + + test 'email confirmation was not sent' do + assert_equal @mails_sent, ActionMailer::Base.deliveries.count + end + + test 'user is confirmed' do + assert @resource.confirmed? + end + end end end diff --git a/test/controllers/devise_token_auth/sessions_controller_test.rb b/test/controllers/devise_token_auth/sessions_controller_test.rb index e21be558d..7dc9458b2 100644 --- a/test/controllers/devise_token_auth/sessions_controller_test.rb +++ b/test/controllers/devise_token_auth/sessions_controller_test.rb @@ -73,9 +73,58 @@ class DeviseTokenAuth::SessionsControllerTest < ActionController::TestCase end end + describe 'get sign_in is not supported' do + before do + xhr :get, :new, { + nickname: @existing_user.nickname, + password: 'secret123' + } + @data = JSON.parse(response.body) + end + + test 'user is notified that they should use post sign_in to authenticate' do + assert_equal 405, response.status + end + test "response should contain errors" do + assert @data['errors'] + assert_equal @data['errors'], [I18n.t("devise_token_auth.sessions.not_supported")] + end + end + + describe 'header sign_in is supported' do + before do + request.headers.merge!( + 'email' => @existing_user.email, + 'password' => 'secret123') + + xhr :head, :create + @data = JSON.parse(response.body) + end + + test 'user can sign in using header request' do + assert_equal 200, response.status + end + end + + describe 'alt auth keys' do + before do + xhr :post, :create, { + nickname: @existing_user.nickname, + password: 'secret123' + } + @data = JSON.parse(response.body) + end + + test 'user can sign in using nickname' do + assert_equal 200, response.status + assert_equal @existing_user.email, @data['data']['email'] + end + end describe 'authed user sign out' do before do + def @controller.reset_session_called; @reset_session_called == true; end + def @controller.reset_session; @reset_session_called = true; end @auth_headers = @existing_user.create_new_auth_token request.headers.merge!(@auth_headers) xhr :delete, :destroy, format: :json @@ -89,17 +138,27 @@ class DeviseTokenAuth::SessionsControllerTest < ActionController::TestCase @existing_user.reload refute @existing_user.tokens[@auth_headers["client"]] end + + test "session was destroyed" do + assert_equal true, @controller.reset_session_called + end end describe 'unauthed user sign out' do before do @auth_headers = @existing_user.create_new_auth_token xhr :delete, :destroy, format: :json + @data = JSON.parse(response.body) end test "unauthed request returns 404" do assert_equal 404, response.status end + + test "response should contain errors" do + assert @data['errors'] + assert_equal @data['errors'], [I18n.t("devise_token_auth.sessions.user_not_found")] + end end describe 'failure' do @@ -119,6 +178,38 @@ class DeviseTokenAuth::SessionsControllerTest < ActionController::TestCase test "response should contain errors" do assert @data['errors'] + assert_equal @data['errors'], [I18n.t("devise_token_auth.sessions.bad_credentials")] + end + end + + describe 'failure with bad password when change_headers_on_each_request false' do + before do + DeviseTokenAuth.change_headers_on_each_request = false + + # accessing current_user calls through set_user_by_token, + # which initializes client_id + @controller.current_user + + xhr :post, :create, { + email: @existing_user.email, + password: 'bogus' + } + + @resource = assigns(:resource) + @data = JSON.parse(response.body) + end + + test "request should fail" do + assert_equal 401, response.status + end + + test "response should contain errors" do + assert @data['errors'] + assert_equal @data['errors'], [I18n.t("devise_token_auth.sessions.bad_credentials")] + end + + after do + DeviseTokenAuth.change_headers_on_each_request = true end end @@ -162,6 +253,59 @@ class DeviseTokenAuth::SessionsControllerTest < ActionController::TestCase assert_equal 401, response.status end + test "response should contain errors" do + assert @data['errors'] + assert_equal @data['errors'], [I18n.t("devise_token_auth.sessions.not_confirmed", email: @unconfirmed_user.email)] + end + end + + describe "Unconfirmed user with allowed unconfirmed access" do + before do + @original_duration = Devise.allow_unconfirmed_access_for + Devise.allow_unconfirmed_access_for = 3.days + @recent_unconfirmed_user = users(:recent_unconfirmed_email_user) + xhr :post, :create, { + email: @recent_unconfirmed_user.email, + password: 'secret123' + } + @resource = assigns(:resource) + @data = JSON.parse(response.body) + end + + after do + Devise.allow_unconfirmed_access_for = @original_duration + end + + test "request should succeed" do + assert_equal 200, response.status + end + + test "request should return user data" do + assert_equal @recent_unconfirmed_user.email, @data['data']['email'] + end + end + + describe "Unconfirmed user with expired unconfirmed access" do + before do + @original_duration = Devise.allow_unconfirmed_access_for + Devise.allow_unconfirmed_access_for = 3.days + @unconfirmed_user = users(:unconfirmed_email_user) + xhr :post, :create, { + email: @unconfirmed_user.email, + password: 'secret123' + } + @resource = assigns(:resource) + @data = JSON.parse(response.body) + end + + after do + Devise.allow_unconfirmed_access_for = @original_duration + end + + test "request should fail" do + assert_equal 401, response.status + end + test "response should contain errors" do assert @data['errors'] end @@ -217,5 +361,122 @@ class DeviseTokenAuth::SessionsControllerTest < ActionController::TestCase assert_equal @existing_user.email, @data['data']['email'] end end + + describe 'User with only :database_authenticatable and :registerable included' do + setup do + @request.env['devise.mapping'] = Devise.mappings[:only_email_user] + end + + teardown do + @request.env['devise.mapping'] = Devise.mappings[:user] + end + + before do + @existing_user = only_email_users(:user) + @existing_user.save! + + xhr :post, :create, { + email: @existing_user.email, + password: 'secret123' + } + + @resource = assigns(:resource) + @data = JSON.parse(response.body) + end + + test 'user should be able to sign in without confirmation' do + assert 200, response.status + refute OnlyEmailUser.method_defined?(:confirmed_at) + end + end + + describe "Lockable User" do + setup do + @request.env['devise.mapping'] = Devise.mappings[:lockable_user] + end + + teardown do + @request.env['devise.mapping'] = Devise.mappings[:user] + end + + before do + @original_lock_strategy = Devise.lock_strategy + @original_unlock_strategy = Devise.unlock_strategy + @original_maximum_attempts = Devise.maximum_attempts + Devise.lock_strategy = :failed_attempts + Devise.unlock_strategy = :email + Devise.maximum_attempts = 5 + end + + after do + Devise.lock_strategy = @original_lock_strategy + Devise.maximum_attempts = @original_maximum_attempts + Devise.unlock_strategy = @original_unlock_strategy + end + + describe "locked user" do + before do + @locked_user = lockable_users(:locked_user) + xhr :post, :create, { + email: @locked_user.email, + password: 'secret123' + } + @data = JSON.parse(response.body) + end + + test "request should fail" do + assert_equal 401, response.status + end + + test "response should contain errors" do + assert @data['errors'] + assert_equal @data['errors'], [I18n.t("devise_token_auth.sessions.not_confirmed", email: @locked_user.email)] + end + end + + describe "unlocked user with bad password" do + before do + @unlocked_user = lockable_users(:unlocked_user) + xhr :post, :create, { + email: @unlocked_user.email, + password: 'bad-password' + } + @data = JSON.parse(response.body) + end + + test "request should fail" do + assert_equal 401, response.status + end + + test "should increase failed_attempts" do + assert_equal 1, @unlocked_user.reload.failed_attempts + end + + test "response should contain errors" do + assert @data['errors'] + assert_equal @data['errors'], [I18n.t("devise_token_auth.sessions.bad_credentials")] + end + + describe 'after maximum_attempts should block the user' do + before do + 4.times do + xhr :post, :create, { + email: @unlocked_user.email, + password: 'bad-password' + } + end + @data = JSON.parse(response.body) + end + + test "should increase failed_attempts" do + assert_equal 5, @unlocked_user.reload.failed_attempts + end + + test "should block the user" do + assert_equal true, @unlocked_user.reload.access_locked? + end + end + end + end end end diff --git a/test/controllers/devise_token_auth/token_validations_controller_test.rb b/test/controllers/devise_token_auth/token_validations_controller_test.rb new file mode 100644 index 000000000..8a03c4c9e --- /dev/null +++ b/test/controllers/devise_token_auth/token_validations_controller_test.rb @@ -0,0 +1,91 @@ +require 'test_helper' + +# was the web request successful? +# was the user redirected to the right page? +# was the user successfully authenticated? +# was the correct object stored in the response? +# was the appropriate message delivered in the json payload? + +class DeviseTokenAuth::TokenValidationsControllerTest < ActionDispatch::IntegrationTest + describe DeviseTokenAuth::TokenValidationsController do + before do + @resource = users(:confirmed_email_user) + @resource.skip_confirmation! + @resource.save! + + @auth_headers = @resource.create_new_auth_token + + @token = @auth_headers['access-token'] + @client_id = @auth_headers['client'] + @expiry = @auth_headers['expiry'] + + # ensure that request is not treated as batch request + age_token(@resource, @client_id) + + end + + describe 'vanilla user' do + before do + get '/auth/validate_token', {}, @auth_headers + @resp = JSON.parse(response.body) + end + + test "token valid" do + assert_equal 200, response.status + end + end + + describe 'using namespaces' do + before do + get '/api/v1/auth/validate_token', {}, @auth_headers + @resp = JSON.parse(response.body) + end + + test "token valid" do + assert_equal 200, response.status + end + end + + describe 'failure' do + before do + get '/api/v1/auth/validate_token', {}, @auth_headers.merge({"access-token" => "12345"}) + @resp = JSON.parse(response.body) + end + + test "request should fail" do + assert_equal 401, response.status + end + + test "response should contain errors" do + assert @resp['errors'] + assert_equal @resp['errors'], [I18n.t("devise_token_auth.token_validations.invalid")] + end + end + + end + + describe 'using namespaces with unused resource' do + + before do + @resource = scoped_users(:confirmed_email_user) + @resource.skip_confirmation! + @resource.save! + + @auth_headers = @resource.create_new_auth_token + + @token = @auth_headers['access-token'] + @client_id = @auth_headers['client'] + @expiry = @auth_headers['expiry'] + + # ensure that request is not treated as batch request + age_token(@resource, @client_id) + end + + test "should be successful" do + get '/api_v2/auth/validate_token', {}, @auth_headers + assert_equal 200, response.status + end + + end + +end diff --git a/test/controllers/overrides/omniauth_callbacks_controller_test.rb b/test/controllers/overrides/omniauth_callbacks_controller_test.rb index 65265f0ef..640446202 100644 --- a/test/controllers/overrides/omniauth_callbacks_controller_test.rb +++ b/test/controllers/overrides/omniauth_callbacks_controller_test.rb @@ -23,7 +23,8 @@ class Overrides::OmniauthCallbacksControllerTest < ActionDispatch::IntegrationTe get_via_redirect '/evil_user_auth/facebook', { auth_origin_url: Faker::Internet.url, - favorite_color: @favorite_color + favorite_color: @favorite_color, + omniauth_window_type: 'newWindow' } @resource = assigns(:resource) diff --git a/test/controllers/overrides/passwords_controller_test.rb b/test/controllers/overrides/passwords_controller_test.rb index 6a32c8f0e..e2dce5034 100644 --- a/test/controllers/overrides/passwords_controller_test.rb +++ b/test/controllers/overrides/passwords_controller_test.rb @@ -42,7 +42,7 @@ class Overrides::PasswordsControllerTest < ActionDispatch::IntegrationTest @override_proof = @qs["override_proof"] end - test 'respones should have success redirect status' do + test 'response should have success redirect status' do assert_equal 302, response.status end diff --git a/test/dummy/app/controllers/application_controller.rb b/test/dummy/app/controllers/application_controller.rb index 69b8974e9..bf0f6fb13 100644 --- a/test/dummy/app/controllers/application_controller.rb +++ b/test/dummy/app/controllers/application_controller.rb @@ -3,14 +3,14 @@ class ApplicationController < ActionController::Base before_action :configure_permitted_parameters, if: :devise_controller? - respond_to :json - protected def configure_permitted_parameters - devise_parameter_sanitizer.for(:sign_up) << :operating_thetan - devise_parameter_sanitizer.for(:sign_up) << :favorite_color - devise_parameter_sanitizer.for(:account_update) << :operating_thetan - devise_parameter_sanitizer.for(:account_update) << :favorite_color + permitted_parameters = devise_parameter_sanitizer.instance_values['permitted'] + permitted_parameters[:sign_up] << :operating_thetan + permitted_parameters[:sign_up] << :favorite_color + permitted_parameters[:account_update] << :operating_thetan + permitted_parameters[:account_update] << :favorite_color + permitted_parameters[:account_update] << :current_password end end diff --git a/test/dummy/app/controllers/auth_origin_controller.rb b/test/dummy/app/controllers/auth_origin_controller.rb new file mode 100644 index 000000000..6df99d122 --- /dev/null +++ b/test/dummy/app/controllers/auth_origin_controller.rb @@ -0,0 +1,5 @@ +class AuthOriginController < ApplicationController + def redirected + render :nothing => true + end +end \ No newline at end of file diff --git a/test/dummy/app/controllers/custom/confirmations_controller.rb b/test/dummy/app/controllers/custom/confirmations_controller.rb new file mode 100644 index 000000000..8e29e8976 --- /dev/null +++ b/test/dummy/app/controllers/custom/confirmations_controller.rb @@ -0,0 +1,13 @@ +class Custom::ConfirmationsController < DeviseTokenAuth::ConfirmationsController + + def show + super do |resource| + @show_block_called = true unless resource.nil? + end + end + + def show_block_called? + @show_block_called == true + end + +end diff --git a/test/dummy/app/controllers/custom/omniauth_callbacks_controller.rb b/test/dummy/app/controllers/custom/omniauth_callbacks_controller.rb new file mode 100644 index 000000000..6680f48dc --- /dev/null +++ b/test/dummy/app/controllers/custom/omniauth_callbacks_controller.rb @@ -0,0 +1,13 @@ +class Custom::OmniauthCallbacksController < DeviseTokenAuth::OmniauthCallbacksController + + def omniauth_success + super do |resource| + @omniauth_success_block_called = true unless resource.nil? + end + end + + def omniauth_success_block_called? + @omniauth_success_block_called == true + end + +end diff --git a/test/dummy/app/controllers/custom/passwords_controller.rb b/test/dummy/app/controllers/custom/passwords_controller.rb new file mode 100644 index 000000000..3f7b6a828 --- /dev/null +++ b/test/dummy/app/controllers/custom/passwords_controller.rb @@ -0,0 +1,40 @@ +class Custom::PasswordsController < DeviseTokenAuth::PasswordsController + + def create + super do |resource| + @create_block_called = true unless resource.nil? + end + end + + def edit + super do |resource| + @edit_block_called = true unless resource.nil? + end + end + + def update + super do |resource| + @update_block_called = true unless resource.nil? + end + end + + def create_block_called? + @create_block_called == true + end + + def edit_block_called? + @edit_block_called == true + end + + def update_block_called? + @update_block_called == true + end + + protected + + def render_update_success + render json: {custom: "foo"} + end + + +end diff --git a/test/dummy/app/controllers/custom/registrations_controller.rb b/test/dummy/app/controllers/custom/registrations_controller.rb new file mode 100644 index 000000000..86d98b1d6 --- /dev/null +++ b/test/dummy/app/controllers/custom/registrations_controller.rb @@ -0,0 +1,39 @@ +class Custom::RegistrationsController < DeviseTokenAuth::RegistrationsController + + def create + super do |resource| + @create_block_called = true + end + end + + def update + super do |resource| + @update_block_called = true unless resource.nil? + end + end + + def destroy + super do |resource| + @destroy_block_called = true unless resource.nil? + end + end + + def create_block_called? + @create_block_called == true + end + + def update_block_called? + @update_block_called == true + end + + def destroy_block_called? + @destroy_block_called == true + end + + protected + + def render_create_success + render json: {custom: "foo"} + end + +end diff --git a/test/dummy/app/controllers/custom/sessions_controller.rb b/test/dummy/app/controllers/custom/sessions_controller.rb new file mode 100644 index 000000000..57809020e --- /dev/null +++ b/test/dummy/app/controllers/custom/sessions_controller.rb @@ -0,0 +1,29 @@ +class Custom::SessionsController < DeviseTokenAuth::SessionsController + + def create + super do |resource| + @create_block_called = true unless resource.nil? + end + end + + def destroy + super do |resource| + @destroy_block_called = true unless resource.nil? + end + end + + def create_block_called? + @create_block_called == true + end + + def destroy_block_called? + @destroy_block_called == true + end + + protected + + def render_create_success + render json: {custom: "foo"} + end + +end diff --git a/test/dummy/app/controllers/custom/token_validations_controller.rb b/test/dummy/app/controllers/custom/token_validations_controller.rb new file mode 100644 index 000000000..4bfca82bb --- /dev/null +++ b/test/dummy/app/controllers/custom/token_validations_controller.rb @@ -0,0 +1,19 @@ +class Custom::TokenValidationsController < DeviseTokenAuth::TokenValidationsController + + def validate_token + super do |resource| + @validate_token_block_called = true unless resource.nil? + end + end + + def validate_token_block_called? + @validate_token_block_called == true + end + + protected + + def render_validate_token_success + render json: {custom: "foo"} + end + +end diff --git a/test/dummy/app/controllers/demo_user_controller.rb b/test/dummy/app/controllers/demo_user_controller.rb index 9bf3191b0..a17789fbd 100644 --- a/test/dummy/app/controllers/demo_user_controller.rb +++ b/test/dummy/app/controllers/demo_user_controller.rb @@ -9,4 +9,17 @@ def members_only } }, status: 200 end + + def members_only_remove_token + u = User.find(current_user.id) + u.tokens = {} + u.save! + + render json: { + data: { + message: "Welcome #{current_user.name}", + user: current_user + } + }, status: 200 + end end diff --git a/test/dummy/app/controllers/overrides/registrations_controller.rb b/test/dummy/app/controllers/overrides/registrations_controller.rb index 2d8274992..5c6be0ce4 100644 --- a/test/dummy/app/controllers/overrides/registrations_controller.rb +++ b/test/dummy/app/controllers/overrides/registrations_controller.rb @@ -14,7 +14,7 @@ def update render json: { status: 'error', errors: @resource.errors - }, status: 403 + }, status: 422 end else render json: { diff --git a/test/dummy/app/controllers/overrides/sessions_controller.rb b/test/dummy/app/controllers/overrides/sessions_controller.rb index 06cd691ac..4526dfd5c 100644 --- a/test/dummy/app/controllers/overrides/sessions_controller.rb +++ b/test/dummy/app/controllers/overrides/sessions_controller.rb @@ -3,9 +3,9 @@ class SessionsController < DeviseTokenAuth::SessionsController OVERRIDE_PROOF = "(^^,)" def create - @resource = resource_class.find_by_email(resource_params[:email]) + @resource = resource_class.find_by(email: resource_params[:email]) - if @resource and valid_params? and @resource.valid_password?(resource_params[:password]) and @resource.confirmed? + if @resource and valid_params?(:email, resource_params[:email]) and @resource.valid_password?(resource_params[:password]) and @resource.confirmed? # create client id @client_id = SecureRandom.urlsafe_base64(nil, false) @token = SecureRandom.urlsafe_base64(nil, false) diff --git a/test/dummy/app/models/lockable_user.rb b/test/dummy/app/models/lockable_user.rb new file mode 100644 index 000000000..79e34a6b2 --- /dev/null +++ b/test/dummy/app/models/lockable_user.rb @@ -0,0 +1,5 @@ +class LockableUser < ActiveRecord::Base + # Include default devise modules. + devise :database_authenticatable, :registerable, :lockable + include DeviseTokenAuth::Concerns::User +end diff --git a/test/dummy/app/models/nice_user.rb b/test/dummy/app/models/nice_user.rb new file mode 100644 index 000000000..a151ae1e2 --- /dev/null +++ b/test/dummy/app/models/nice_user.rb @@ -0,0 +1,7 @@ +class NiceUser < ActiveRecord::Base + # Include default devise modules. + devise :database_authenticatable, :registerable, + :recoverable, :rememberable, :trackable, :validatable, + :confirmable, :omniauthable + include DeviseTokenAuth::Concerns::User +end diff --git a/test/dummy/app/models/only_email_user.rb b/test/dummy/app/models/only_email_user.rb new file mode 100644 index 000000000..c6fee9c45 --- /dev/null +++ b/test/dummy/app/models/only_email_user.rb @@ -0,0 +1,5 @@ +class OnlyEmailUser < ActiveRecord::Base + # Include default devise modules. + devise :database_authenticatable, :registerable + include DeviseTokenAuth::Concerns::User +end diff --git a/test/dummy/app/models/scoped_user.rb b/test/dummy/app/models/scoped_user.rb new file mode 100644 index 000000000..5dca1286f --- /dev/null +++ b/test/dummy/app/models/scoped_user.rb @@ -0,0 +1,7 @@ +class ScopedUser < ActiveRecord::Base + # Include default devise modules. + devise :database_authenticatable, :registerable, + :recoverable, :rememberable, :trackable, :validatable, + :confirmable, :omniauthable + include DeviseTokenAuth::Concerns::User +end diff --git a/test/dummy/app/models/unconfirmable_user.rb b/test/dummy/app/models/unconfirmable_user.rb new file mode 100644 index 000000000..64fb15e53 --- /dev/null +++ b/test/dummy/app/models/unconfirmable_user.rb @@ -0,0 +1,8 @@ +class UnconfirmableUser < ActiveRecord::Base + # Include default devise modules. + devise :database_authenticatable, :registerable, + :recoverable, :rememberable, + :trackable, :validatable, + :omniauthable + include DeviseTokenAuth::Concerns::User +end diff --git a/test/dummy/app/models/unregisterable_user.rb b/test/dummy/app/models/unregisterable_user.rb new file mode 100644 index 000000000..44f596d40 --- /dev/null +++ b/test/dummy/app/models/unregisterable_user.rb @@ -0,0 +1,7 @@ +class UnregisterableUser < ActiveRecord::Base + # Include default devise modules. + devise :database_authenticatable, + :recoverable, :trackable, :validatable, + :confirmable, :omniauthable + include DeviseTokenAuth::Concerns::User +end diff --git a/test/dummy/config/application.rb b/test/dummy/config/application.rb index 1fe3dcd98..ff7cd58d8 100644 --- a/test/dummy/config/application.rb +++ b/test/dummy/config/application.rb @@ -19,5 +19,6 @@ class Application < Rails::Application # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded. # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s] # config.i18n.default_locale = :de + config.autoload_paths << Rails.root.join('lib') end end diff --git a/test/dummy/config/environments/production.rb b/test/dummy/config/environments/production.rb index a8836c36c..a6ed58747 100644 --- a/test/dummy/config/environments/production.rb +++ b/test/dummy/config/environments/production.rb @@ -20,7 +20,7 @@ # config.action_dispatch.rack_cache = true # Disable Rails's static asset server (Apache or nginx will already do this). - config.serve_static_assets = false + config.serve_static_files = false # Compress JavaScripts and CSS. config.assets.js_compressor = :uglifier diff --git a/test/dummy/config/environments/test.rb b/test/dummy/config/environments/test.rb index 69acac45f..4fd5b040b 100644 --- a/test/dummy/config/environments/test.rb +++ b/test/dummy/config/environments/test.rb @@ -13,8 +13,13 @@ config.eager_load = false # Configure static asset server for tests with Cache-Control for performance. - config.serve_static_assets = true - config.static_cache_control = 'public, max-age=3600' + Rails::VERSION::MAJOR == 5 ? + (config.public_file_server.enabled = true) : + (config.serve_static_files = true) + + Rails::VERSION::MAJOR == 5 ? + (config.public_file_server.headers = { 'Cache-Control' => 'public, max-age=3600' }) : + (config.static_cache_control = 'public, max-age=3600') # Show full error reports and disable caching. config.consider_all_requests_local = true @@ -37,4 +42,7 @@ # Raises error for missing translations # config.action_view.raise_on_missing_translations = true + + # randomize test order + config.active_support.test_order = :random end diff --git a/test/dummy/config/initializers/devise.rb b/test/dummy/config/initializers/devise.rb new file mode 100644 index 000000000..d5c41f257 --- /dev/null +++ b/test/dummy/config/initializers/devise.rb @@ -0,0 +1,3 @@ +Devise.setup do |config| + config.authentication_keys = [:email, :nickname] +end diff --git a/test/dummy/config/routes.rb b/test/dummy/config/routes.rb index 1e779fbd4..c0b6472ea 100644 --- a/test/dummy/config/routes.rb +++ b/test/dummy/config/routes.rb @@ -4,13 +4,13 @@ # within a `devise_scope` block # define :users as the first devise mapping: - mount_devise_token_auth_for 'User', at: '/auth' + mount_devise_token_auth_for 'User', at: 'auth' # define :mangs as the second devise mapping. routes using this class will # need to be defined within a devise_scope as shown below - mount_devise_token_auth_for "Mang", at: '/mangs' + mount_devise_token_auth_for "Mang", at: 'mangs' - mount_devise_token_auth_for 'EvilUser', at: '/evil_user_auth', controllers: { + mount_devise_token_auth_for 'EvilUser', at: 'evil_user_auth', controllers: { confirmations: 'overrides/confirmations', passwords: 'overrides/passwords', omniauth_callbacks: 'overrides/omniauth_callbacks', @@ -19,12 +19,54 @@ token_validations: 'overrides/token_validations' } + mount_devise_token_auth_for 'NiceUser', at: 'nice_user_auth', controllers: { + registrations: 'custom/registrations', + confirmations: 'custom/confirmations', + passwords: 'custom/passwords', + sessions: 'custom/sessions', + token_validations: 'custom/token_validations', + omniauth_callbacks: 'custom/omniauth_callbacks' + } + + mount_devise_token_auth_for 'OnlyEmailUser', at: 'only_email_auth', skip: [:omniauth_callbacks] + + mount_devise_token_auth_for 'UnregisterableUser', at: 'unregisterable_user_auth', skip: [:registrations] + + mount_devise_token_auth_for 'UnconfirmableUser', at: 'unconfirmable_user_auth' + + mount_devise_token_auth_for 'LockableUser', at: 'lockable_user_auth' + + # test namespacing + namespace :api do + scope :v1 do + mount_devise_token_auth_for 'User', at: 'auth' + end + end + + # test namespacing with not created devise mapping + namespace :api_v2, defaults: { format: :json } do + mount_devise_token_auth_for "ScopedUser", + at: "auth", + controllers: { + omniauth_callbacks: "api_v2/omniauth_callbacks", + sessions: "api_v2/sessions", + registrations: "api_v2/registrations", + confirmations: "api_v2/confirmations", + passwords: "api_v2/passwords" + } + end + # this route will authorize visitors using the User class get 'demo/members_only', to: 'demo_user#members_only' + get 'demo/members_only_remove_token', to: 'demo_user#members_only_remove_token' + # routes within this block will authorize visitors using the Mang class get 'demo/members_only_mang', to: 'demo_mang#members_only' # routes within this block will authorize visitors using the Mang or User class get 'demo/members_only_group', to: 'demo_group#members_only' + + # we need a route for omniauth_callback_controller to redirect to in sameWindow case + get 'auth_origin', to: 'auth_origin#redirected' end diff --git a/test/dummy/db/migrate/20140715061447_devise_token_auth_create_users.rb b/test/dummy/db/migrate/20140715061447_devise_token_auth_create_users.rb index 1406f1e1b..c6227fa45 100644 --- a/test/dummy/db/migrate/20140715061447_devise_token_auth_create_users.rb +++ b/test/dummy/db/migrate/20140715061447_devise_token_auth_create_users.rb @@ -1,3 +1,5 @@ +include MigrationDatabaseHelper + class DeviseTokenAuthCreateUsers < ActiveRecord::Migration def change create_table(:users) do |t| @@ -42,7 +44,11 @@ def change t.string :uid, :null => false, :default => "" ## Tokens - t.text :tokens + if json_supported_database? + t.json :tokens + else + t.text :tokens + end t.timestamps end @@ -51,6 +57,7 @@ def change add_index :users, [:uid, :provider], :unique => true add_index :users, :reset_password_token, :unique => true add_index :users, :confirmation_token, :unique => true + add_index :users, :nickname, :unique => true # add_index :users, :unlock_token, :unique => true end end diff --git a/test/dummy/db/migrate/20140715061805_devise_token_auth_create_mangs.rb b/test/dummy/db/migrate/20140715061805_devise_token_auth_create_mangs.rb index 7337c7cad..628ad8af4 100644 --- a/test/dummy/db/migrate/20140715061805_devise_token_auth_create_mangs.rb +++ b/test/dummy/db/migrate/20140715061805_devise_token_auth_create_mangs.rb @@ -1,3 +1,5 @@ +include MigrationDatabaseHelper + class DeviseTokenAuthCreateMangs < ActiveRecord::Migration def change create_table(:mangs) do |t| @@ -42,7 +44,11 @@ def change t.string :uid, :null => false, :default => "" ## Tokens - t.text :tokens + if json_supported_database? + t.json :tokens + else + t.text :tokens + end t.timestamps end diff --git a/test/dummy/db/migrate/20140928231203_devise_token_auth_create_evil_users.rb b/test/dummy/db/migrate/20140928231203_devise_token_auth_create_evil_users.rb index f5fd9aabf..8bc60b8cf 100644 --- a/test/dummy/db/migrate/20140928231203_devise_token_auth_create_evil_users.rb +++ b/test/dummy/db/migrate/20140928231203_devise_token_auth_create_evil_users.rb @@ -1,3 +1,5 @@ +include MigrationDatabaseHelper + class DeviseTokenAuthCreateEvilUsers < ActiveRecord::Migration def change create_table(:evil_users) do |t| @@ -40,7 +42,11 @@ def change t.string :uid, :null => false, :default => "" ## Tokens - t.text :tokens + if json_supported_database? + t.json :tokens + else + t.text :tokens + end ## etc. t.string :favorite_color diff --git a/test/dummy/db/migrate/20141222035835_devise_token_auth_create_only_email_users.rb b/test/dummy/db/migrate/20141222035835_devise_token_auth_create_only_email_users.rb new file mode 100644 index 000000000..6c25075fa --- /dev/null +++ b/test/dummy/db/migrate/20141222035835_devise_token_auth_create_only_email_users.rb @@ -0,0 +1,60 @@ +include MigrationDatabaseHelper + +class DeviseTokenAuthCreateOnlyEmailUsers < ActiveRecord::Migration + def change + create_table(:only_email_users) do |t| + ## Required + t.string :provider, :null => false + t.string :uid, :null => false, :default => "" + + ## Database authenticatable + t.string :encrypted_password, :null => false, :default => "" + + ## Recoverable + #t.string :reset_password_token + #t.datetime :reset_password_sent_at + + ## Rememberable + #t.datetime :remember_created_at + + ## Trackable + #t.integer :sign_in_count, :default => 0, :null => false + #t.datetime :current_sign_in_at + #t.datetime :last_sign_in_at + #t.string :current_sign_in_ip + #t.string :last_sign_in_ip + + ## Confirmable + #t.string :confirmation_token + #t.datetime :confirmed_at + #t.datetime :confirmation_sent_at + #t.string :unconfirmed_email # Only if using reconfirmable + + ## Lockable + # t.integer :failed_attempts, :default => 0, :null => false # Only if lock strategy is :failed_attempts + # t.string :unlock_token # Only if unlock strategy is :email or :both + # t.datetime :locked_at + + ## User Info + t.string :name + t.string :nickname + t.string :image + t.string :email + + ## Tokens + if json_supported_database? + t.json :tokens + else + t.text :tokens + end + + t.timestamps + end + + add_index :only_email_users, :email + add_index :only_email_users, [:uid, :provider], :unique => true + #add_index :only_email_users, :reset_password_token, :unique => true + # add_index :only_email_users, :confirmation_token, :unique => true + # add_index :only_email_users, :unlock_token, :unique => true + end +end diff --git a/test/dummy/db/migrate/20141222053502_devise_token_auth_create_unregisterable_users.rb b/test/dummy/db/migrate/20141222053502_devise_token_auth_create_unregisterable_users.rb new file mode 100644 index 000000000..aa7cb7ec7 --- /dev/null +++ b/test/dummy/db/migrate/20141222053502_devise_token_auth_create_unregisterable_users.rb @@ -0,0 +1,60 @@ +include MigrationDatabaseHelper + +class DeviseTokenAuthCreateUnregisterableUsers < ActiveRecord::Migration + def change + create_table(:unregisterable_users) do |t| + ## Required + t.string :provider, :null => false + t.string :uid, :null => false, :default => "" + + ## Database authenticatable + t.string :encrypted_password, :null => false, :default => "" + + ## Recoverable + t.string :reset_password_token + t.datetime :reset_password_sent_at + + ## Rememberable + t.datetime :remember_created_at + + ## Trackable + t.integer :sign_in_count, :default => 0, :null => false + t.datetime :current_sign_in_at + t.datetime :last_sign_in_at + t.string :current_sign_in_ip + t.string :last_sign_in_ip + + ## Confirmable + t.string :confirmation_token + t.datetime :confirmed_at + t.datetime :confirmation_sent_at + t.string :unconfirmed_email # Only if using reconfirmable + + ## Lockable + # t.integer :failed_attempts, :default => 0, :null => false # Only if lock strategy is :failed_attempts + # t.string :unlock_token # Only if unlock strategy is :email or :both + # t.datetime :locked_at + + ## User Info + t.string :name + t.string :nickname + t.string :image + t.string :email + + ## Tokens + if json_supported_database? + t.json :tokens + else + t.text :tokens + end + + t.timestamps + end + + add_index :unregisterable_users, :email + add_index :unregisterable_users, [:uid, :provider], :unique => true + add_index :unregisterable_users, :reset_password_token, :unique => true + # add_index :unregisterable_users, :confirmation_token, :unique => true + # add_index :unregisterable_users, :unlock_token, :unique => true + end +end diff --git a/test/dummy/db/migrate/20150409095712_devise_token_auth_create_nice_users.rb b/test/dummy/db/migrate/20150409095712_devise_token_auth_create_nice_users.rb new file mode 100644 index 000000000..0b237452e --- /dev/null +++ b/test/dummy/db/migrate/20150409095712_devise_token_auth_create_nice_users.rb @@ -0,0 +1,60 @@ +include MigrationDatabaseHelper + +class DeviseTokenAuthCreateNiceUsers < ActiveRecord::Migration + def change + create_table(:nice_users) do |t| + ## Required + t.string :provider, :null => false + t.string :uid, :null => false, :default => "" + + ## Database authenticatable + t.string :encrypted_password, :null => false, :default => "" + + ## Recoverable + t.string :reset_password_token + t.datetime :reset_password_sent_at + + ## Rememberable + t.datetime :remember_created_at + + ## Trackable + t.integer :sign_in_count, :default => 0, :null => false + t.datetime :current_sign_in_at + t.datetime :last_sign_in_at + t.string :current_sign_in_ip + t.string :last_sign_in_ip + + ## Confirmable + t.string :confirmation_token + t.datetime :confirmed_at + t.datetime :confirmation_sent_at + t.string :unconfirmed_email # Only if using reconfirmable + + ## Lockable + # t.integer :failed_attempts, :default => 0, :null => false # Only if lock strategy is :failed_attempts + # t.string :unlock_token # Only if unlock strategy is :email or :both + # t.datetime :locked_at + + ## User Info + t.string :name + t.string :nickname + t.string :image + t.string :email + + ## Tokens + if json_supported_database? + t.json :tokens + else + t.text :tokens + end + + t.timestamps + end + + add_index :nice_users, :email + add_index :nice_users, [:uid, :provider], :unique => true + add_index :nice_users, :reset_password_token, :unique => true + # add_index :nice_users, :confirmation_token, :unique => true + # add_index :nice_users, :unlock_token, :unique => true + end +end diff --git a/test/dummy/db/migrate/20150708104536_devise_token_auth_create_unconfirmable_users.rb b/test/dummy/db/migrate/20150708104536_devise_token_auth_create_unconfirmable_users.rb new file mode 100644 index 000000000..af0a224a7 --- /dev/null +++ b/test/dummy/db/migrate/20150708104536_devise_token_auth_create_unconfirmable_users.rb @@ -0,0 +1,60 @@ +include MigrationDatabaseHelper + +class DeviseTokenAuthCreateUnconfirmableUsers < ActiveRecord::Migration + def change + create_table(:unconfirmable_users) do |t| + ## Required + t.string :provider, :null => false + t.string :uid, :null => false, :default => "" + + ## Database authenticatable + t.string :encrypted_password, :null => false, :default => "" + + ## Recoverable + t.string :reset_password_token + t.datetime :reset_password_sent_at + + ## Rememberable + t.datetime :remember_created_at + + ## Trackable + t.integer :sign_in_count, :default => 0, :null => false + t.datetime :current_sign_in_at + t.datetime :last_sign_in_at + t.string :current_sign_in_ip + t.string :last_sign_in_ip + + ## Confirmable + # t.string :confirmation_token + # t.datetime :confirmed_at + # t.datetime :confirmation_sent_at + # t.string :unconfirmed_email # Only if using reconfirmable + + ## Lockable + # t.integer :failed_attempts, :default => 0, :null => false # Only if lock strategy is :failed_attempts + # t.string :unlock_token # Only if unlock strategy is :email or :both + # t.datetime :locked_at + + ## User Info + t.string :name + t.string :nickname + t.string :image + t.string :email + + ## Tokens + if json_supported_database? + t.json :tokens + else + t.text :tokens + end + + t.timestamps + end + + add_index :unconfirmable_users, :email + add_index :unconfirmable_users, [:uid, :provider], :unique => true + add_index :unconfirmable_users, :reset_password_token, :unique => true + # add_index :nice_users, :confirmation_token, :unique => true + # add_index :nice_users, :unlock_token, :unique => true + end +end diff --git a/test/dummy/db/migrate/20160103235141_devise_token_auth_create_scoped_users.rb b/test/dummy/db/migrate/20160103235141_devise_token_auth_create_scoped_users.rb new file mode 100644 index 000000000..0b2a9320f --- /dev/null +++ b/test/dummy/db/migrate/20160103235141_devise_token_auth_create_scoped_users.rb @@ -0,0 +1,60 @@ +include MigrationDatabaseHelper + +class DeviseTokenAuthCreateScopedUsers < ActiveRecord::Migration + def change + create_table(:scoped_users) do |t| + ## Required + t.string :provider, :null => false + t.string :uid, :null => false, :default => "" + + ## Database authenticatable + t.string :encrypted_password, :null => false, :default => "" + + ## Recoverable + t.string :reset_password_token + t.datetime :reset_password_sent_at + + ## Rememberable + t.datetime :remember_created_at + + ## Trackable + t.integer :sign_in_count, :default => 0, :null => false + t.datetime :current_sign_in_at + t.datetime :last_sign_in_at + t.string :current_sign_in_ip + t.string :last_sign_in_ip + + ## Confirmable + t.string :confirmation_token + t.datetime :confirmed_at + t.datetime :confirmation_sent_at + t.string :unconfirmed_email # Only if using reconfirmable + + ## Lockable + # t.integer :failed_attempts, :default => 0, :null => false # Only if lock strategy is :failed_attempts + # t.string :unlock_token # Only if unlock strategy is :email or :both + # t.datetime :locked_at + + ## User Info + t.string :name + t.string :nickname + t.string :image + t.string :email + + ## Tokens + if json_supported_database? + t.json :tokens + else + t.text :tokens + end + + t.timestamps + end + + add_index :scoped_users, :email + add_index :scoped_users, [:uid, :provider], :unique => true + add_index :scoped_users, :reset_password_token, :unique => true + # add_index :scoped_users, :confirmation_token, :unique => true + # add_index :scoped_users, :unlock_token, :unique => true + end +end diff --git a/test/dummy/db/migrate/20160629184441_devise_token_auth_create_lockable_users.rb b/test/dummy/db/migrate/20160629184441_devise_token_auth_create_lockable_users.rb new file mode 100644 index 000000000..460c0a22d --- /dev/null +++ b/test/dummy/db/migrate/20160629184441_devise_token_auth_create_lockable_users.rb @@ -0,0 +1,60 @@ +include MigrationDatabaseHelper + +class DeviseTokenAuthCreateLockableUsers < ActiveRecord::Migration + def change + create_table(:lockable_users) do |t| + ## Required + t.string :provider, :null => false + t.string :uid, :null => false, :default => "" + + ## Database authenticatable + t.string :encrypted_password, :null => false, :default => "" + + ## Recoverable + # t.string :reset_password_token + # t.datetime :reset_password_sent_at + + ## Rememberable + # t.datetime :remember_created_at + + ## Trackable + # t.integer :sign_in_count, :default => 0, :null => false + # t.datetime :current_sign_in_at + # t.datetime :last_sign_in_at + # t.string :current_sign_in_ip + # t.string :last_sign_in_ip + + ## Confirmable + # t.string :confirmation_token + # t.datetime :confirmed_at + # t.datetime :confirmation_sent_at + # t.string :unconfirmed_email # Only if using reconfirmable + + ## Lockable + t.integer :failed_attempts, :default => 0, :null => false # Only if lock strategy is :failed_attempts + t.string :unlock_token # Only if unlock strategy is :email or :both + t.datetime :locked_at + + ## User Info + t.string :name + t.string :nickname + t.string :image + t.string :email + + ## Tokens + if json_supported_database? + t.json :tokens + else + t.text :tokens + end + + t.timestamps + end + + add_index :lockable_users, :email + add_index :lockable_users, [:uid, :provider], :unique => true + # add_index :lockable_users, :reset_password_token, :unique => true + # add_index :lockable_users, :confirmation_token, :unique => true + add_index :lockable_users, :unlock_token, :unique => true + end +end diff --git a/test/dummy/db/schema.rb b/test/dummy/db/schema.rb index 3f259bd3a..6e5b299b1 100644 --- a/test/dummy/db/schema.rb +++ b/test/dummy/db/schema.rb @@ -11,9 +11,9 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20140928231203) do +ActiveRecord::Schema.define(version: 20160629184441) do - create_table "evil_users", force: true do |t| + create_table "evil_users", force: :cascade do |t| t.string "email" t.string "encrypted_password", default: "", null: false t.string "reset_password_token" @@ -39,12 +39,32 @@ t.datetime "updated_at" end - add_index "evil_users", ["confirmation_token"], name: "index_evil_users_on_confirmation_token", unique: true, using: :btree - add_index "evil_users", ["email"], name: "index_evil_users_on_email", using: :btree - add_index "evil_users", ["reset_password_token"], name: "index_evil_users_on_reset_password_token", unique: true, using: :btree - add_index "evil_users", ["uid", "provider"], name: "index_evil_users_on_uid_and_provider", unique: true, using: :btree + add_index "evil_users", ["confirmation_token"], name: "index_evil_users_on_confirmation_token", unique: true + add_index "evil_users", ["email"], name: "index_evil_users_on_email" + add_index "evil_users", ["reset_password_token"], name: "index_evil_users_on_reset_password_token", unique: true + add_index "evil_users", ["uid", "provider"], name: "index_evil_users_on_uid_and_provider", unique: true - create_table "mangs", force: true do |t| + create_table "lockable_users", force: :cascade do |t| + t.string "provider", null: false + t.string "uid", default: "", null: false + t.string "encrypted_password", default: "", null: false + t.integer "failed_attempts", default: 0, null: false + t.string "unlock_token" + t.datetime "locked_at" + t.string "name" + t.string "nickname" + t.string "image" + t.string "email" + t.text "tokens" + t.datetime "created_at" + t.datetime "updated_at" + end + + add_index "lockable_users", ["email"], name: "index_lockable_users_on_email" + add_index "lockable_users", ["uid", "provider"], name: "index_lockable_users_on_uid_and_provider", unique: true + add_index "lockable_users", ["unlock_token"], name: "index_lockable_users_on_unlock_token", unique: true + + create_table "mangs", force: :cascade do |t| t.string "email" t.string "encrypted_password", default: "", null: false t.string "reset_password_token" @@ -72,12 +92,140 @@ t.string "favorite_color" end - add_index "mangs", ["confirmation_token"], name: "index_mangs_on_confirmation_token", unique: true, using: :btree - add_index "mangs", ["email"], name: "index_mangs_on_email", using: :btree - add_index "mangs", ["reset_password_token"], name: "index_mangs_on_reset_password_token", unique: true, using: :btree - add_index "mangs", ["uid", "provider"], name: "index_mangs_on_uid_and_provider", unique: true, using: :btree + add_index "mangs", ["confirmation_token"], name: "index_mangs_on_confirmation_token", unique: true + add_index "mangs", ["email"], name: "index_mangs_on_email" + add_index "mangs", ["reset_password_token"], name: "index_mangs_on_reset_password_token", unique: true + add_index "mangs", ["uid", "provider"], name: "index_mangs_on_uid_and_provider", unique: true + + create_table "nice_users", force: :cascade do |t| + t.string "provider", null: false + t.string "uid", default: "", null: false + t.string "encrypted_password", default: "", null: false + t.string "reset_password_token" + t.datetime "reset_password_sent_at" + t.datetime "remember_created_at" + t.integer "sign_in_count", default: 0, null: false + t.datetime "current_sign_in_at" + t.datetime "last_sign_in_at" + t.string "current_sign_in_ip" + t.string "last_sign_in_ip" + t.string "confirmation_token" + t.datetime "confirmed_at" + t.datetime "confirmation_sent_at" + t.string "unconfirmed_email" + t.string "name" + t.string "nickname" + t.string "image" + t.string "email" + t.text "tokens" + t.datetime "created_at" + t.datetime "updated_at" + end + + add_index "nice_users", ["email"], name: "index_nice_users_on_email" + add_index "nice_users", ["reset_password_token"], name: "index_nice_users_on_reset_password_token", unique: true + add_index "nice_users", ["uid", "provider"], name: "index_nice_users_on_uid_and_provider", unique: true + + create_table "only_email_users", force: :cascade do |t| + t.string "provider", null: false + t.string "uid", default: "", null: false + t.string "encrypted_password", default: "", null: false + t.string "name" + t.string "nickname" + t.string "image" + t.string "email" + t.text "tokens" + t.datetime "created_at" + t.datetime "updated_at" + end + + add_index "only_email_users", ["email"], name: "index_only_email_users_on_email" + add_index "only_email_users", ["uid", "provider"], name: "index_only_email_users_on_uid_and_provider", unique: true + + create_table "scoped_users", force: :cascade do |t| + t.string "provider", null: false + t.string "uid", default: "", null: false + t.string "encrypted_password", default: "", null: false + t.string "reset_password_token" + t.datetime "reset_password_sent_at" + t.datetime "remember_created_at" + t.integer "sign_in_count", default: 0, null: false + t.datetime "current_sign_in_at" + t.datetime "last_sign_in_at" + t.string "current_sign_in_ip" + t.string "last_sign_in_ip" + t.string "confirmation_token" + t.datetime "confirmed_at" + t.datetime "confirmation_sent_at" + t.string "unconfirmed_email" + t.string "name" + t.string "nickname" + t.string "image" + t.string "email" + t.text "tokens" + t.datetime "created_at" + t.datetime "updated_at" + end + + add_index "scoped_users", ["email"], name: "index_scoped_users_on_email" + add_index "scoped_users", ["reset_password_token"], name: "index_scoped_users_on_reset_password_token", unique: true + add_index "scoped_users", ["uid", "provider"], name: "index_scoped_users_on_uid_and_provider", unique: true + + create_table "unconfirmable_users", force: :cascade do |t| + t.string "provider", null: false + t.string "uid", default: "", null: false + t.string "encrypted_password", default: "", null: false + t.string "reset_password_token" + t.datetime "reset_password_sent_at" + t.datetime "remember_created_at" + t.integer "sign_in_count", default: 0, null: false + t.datetime "current_sign_in_at" + t.datetime "last_sign_in_at" + t.string "current_sign_in_ip" + t.string "last_sign_in_ip" + t.string "name" + t.string "nickname" + t.string "image" + t.string "email" + t.text "tokens" + t.datetime "created_at" + t.datetime "updated_at" + end + + add_index "unconfirmable_users", ["email"], name: "index_unconfirmable_users_on_email" + add_index "unconfirmable_users", ["reset_password_token"], name: "index_unconfirmable_users_on_reset_password_token", unique: true + add_index "unconfirmable_users", ["uid", "provider"], name: "index_unconfirmable_users_on_uid_and_provider", unique: true + + create_table "unregisterable_users", force: :cascade do |t| + t.string "provider", null: false + t.string "uid", default: "", null: false + t.string "encrypted_password", default: "", null: false + t.string "reset_password_token" + t.datetime "reset_password_sent_at" + t.datetime "remember_created_at" + t.integer "sign_in_count", default: 0, null: false + t.datetime "current_sign_in_at" + t.datetime "last_sign_in_at" + t.string "current_sign_in_ip" + t.string "last_sign_in_ip" + t.string "confirmation_token" + t.datetime "confirmed_at" + t.datetime "confirmation_sent_at" + t.string "unconfirmed_email" + t.string "name" + t.string "nickname" + t.string "image" + t.string "email" + t.text "tokens" + t.datetime "created_at" + t.datetime "updated_at" + end + + add_index "unregisterable_users", ["email"], name: "index_unregisterable_users_on_email" + add_index "unregisterable_users", ["reset_password_token"], name: "index_unregisterable_users_on_reset_password_token", unique: true + add_index "unregisterable_users", ["uid", "provider"], name: "index_unregisterable_users_on_uid_and_provider", unique: true - create_table "users", force: true do |t| + create_table "users", force: :cascade do |t| t.string "email" t.string "encrypted_password", default: "", null: false t.string "reset_password_token" @@ -106,9 +254,10 @@ t.string "favorite_color" end - add_index "users", ["confirmation_token"], name: "index_users_on_confirmation_token", unique: true, using: :btree - add_index "users", ["email"], name: "index_users_on_email", using: :btree - add_index "users", ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true, using: :btree - add_index "users", ["uid", "provider"], name: "index_users_on_uid_and_provider", unique: true, using: :btree + add_index "users", ["confirmation_token"], name: "index_users_on_confirmation_token", unique: true + add_index "users", ["email"], name: "index_users_on_email" + add_index "users", ["nickname"], name: "index_users_on_nickname", unique: true + add_index "users", ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true + add_index "users", ["uid", "provider"], name: "index_users_on_uid_and_provider", unique: true end diff --git a/test/dummy/lib/migration_database_helper.rb b/test/dummy/lib/migration_database_helper.rb new file mode 100644 index 000000000..bdfc3f517 --- /dev/null +++ b/test/dummy/lib/migration_database_helper.rb @@ -0,0 +1,29 @@ +module MigrationDatabaseHelper + def json_supported_database? + (postgres? && postgres_correct_version?) || (mysql? && mysql_correct_version?) + end + + def postgres? + database_name == 'ActiveRecord::ConnectionAdapters::PostgreSQLAdapter' + end + + def postgres_correct_version? + database_version > '9.3' + end + + def mysql? + database_name == 'ActiveRecord::ConnectionAdapters::MysqlAdapter' + end + + def mysql_correct_version? + database_version > '5.7.7' + end + + def database_name + ActiveRecord::Base.connection.class.name + end + + def database_version + ActiveRecord::Base.connection.select_value('SELECT VERSION()') + end +end \ No newline at end of file diff --git a/test/fixtures/lockable_users.yml b/test/fixtures/lockable_users.yml new file mode 100644 index 000000000..7a299b32f --- /dev/null +++ b/test/fixtures/lockable_users.yml @@ -0,0 +1,22 @@ +<% @locked_user = Faker::Internet.email %> +<% timestamp = DateTime.parse(1.day.ago.to_s).to_time.strftime("%F %T") %> +unlocked_user: + uid: "<%= @locked_user %>" + email: "<%= @locked_user %>" + provider: 'email' + created_at: '<%= timestamp %>' + updated_at: '<%= timestamp %>' + encrypted_password: <%= User.new.send(:password_digest, 'secret123') %> + +<% @locked_user = Faker::Internet.email %> +<% timestamp = DateTime.parse(1.day.ago.to_s).to_time.strftime("%F %T") %> +locked_user: + uid: "<%= @locked_user %>" + email: "<%= @locked_user %>" + provider: 'email' + created_at: '<%= timestamp %>' + updated_at: '<%= timestamp %>' + encrypted_password: <%= User.new.send(:password_digest, 'secret123') %> + locked_at: '<%= timestamp %>' + failed_attempts: 5 + diff --git a/test/fixtures/nice_users.yml b/test/fixtures/nice_users.yml new file mode 100644 index 000000000..bc84324f1 --- /dev/null +++ b/test/fixtures/nice_users.yml @@ -0,0 +1,29 @@ +<% timestamp = DateTime.parse(2.weeks.ago.to_s).to_time.strftime("%F %T") %> +<% @email = Faker::Internet.email %> +confirmed_email_user: + uid: "<%= @email %>" + email: "<%= @email %>" + provider: 'email' + confirmed_at: '<%= timestamp %>' + created_at: '<%= timestamp %>' + updated_at: '<%= timestamp %>' + encrypted_password: <%= User.new.send(:password_digest, 'secret123') %> + +<% @fb_email = Faker::Internet.email %> +duplicate_email_facebook_user: + uid: "<%= Faker::Number.number(10) %>" + email: "<%= @fb_email %>" + provider: 'facebook' + created_at: '<%= timestamp %>' + updated_at: '<%= timestamp %>' + confirmed_at: '<%= timestamp %>' + encrypted_password: <%= User.new.send(:password_digest, 'secret123') %> + +<% @unconfirmed_email = Faker::Internet.email %> +unconfirmed_email_user: + uid: "<%= @unconfirmed_email %>" + email: "<%= @unconfirmed_email %>" + provider: 'email' + created_at: '<%= timestamp %>' + updated_at: '<%= timestamp %>' + encrypted_password: <%= User.new.send(:password_digest, 'secret123') %> diff --git a/test/fixtures/only_email_users.yml b/test/fixtures/only_email_users.yml new file mode 100644 index 000000000..7c0117bff --- /dev/null +++ b/test/fixtures/only_email_users.yml @@ -0,0 +1,9 @@ +<% timestamp = DateTime.parse(2.weeks.ago.to_s).to_time.strftime("%F %T") %> +<% @email = Faker::Internet.email %> +user: + uid: "<%= @email %>" + email: "<%= @email %>" + provider: 'email' + created_at: '<%= timestamp %>' + updated_at: '<%= timestamp %>' + encrypted_password: <%= User.new.send(:password_digest, 'secret123') %> diff --git a/test/fixtures/scoped_users.yml b/test/fixtures/scoped_users.yml new file mode 100644 index 000000000..cfb26e762 --- /dev/null +++ b/test/fixtures/scoped_users.yml @@ -0,0 +1,10 @@ +<% timestamp = DateTime.parse(2.weeks.ago.to_s).to_time.strftime("%F %T") %> +<% @email = Faker::Internet.email %> +confirmed_email_user: + uid: "<%= @email %>" + email: "<%= @email %>" + provider: 'email' + confirmed_at: '<%= timestamp %>' + created_at: '<%= timestamp %>' + updated_at: '<%= timestamp %>' + encrypted_password: <%= User.new.send(:password_digest, 'secret123') %> diff --git a/test/fixtures/unconfirmable_users.yml b/test/fixtures/unconfirmable_users.yml new file mode 100644 index 000000000..7c0117bff --- /dev/null +++ b/test/fixtures/unconfirmable_users.yml @@ -0,0 +1,9 @@ +<% timestamp = DateTime.parse(2.weeks.ago.to_s).to_time.strftime("%F %T") %> +<% @email = Faker::Internet.email %> +user: + uid: "<%= @email %>" + email: "<%= @email %>" + provider: 'email' + created_at: '<%= timestamp %>' + updated_at: '<%= timestamp %>' + encrypted_password: <%= User.new.send(:password_digest, 'secret123') %> diff --git a/test/fixtures/users.yml b/test/fixtures/users.yml index bc84324f1..fa65e199d 100644 --- a/test/fixtures/users.yml +++ b/test/fixtures/users.yml @@ -1,29 +1,53 @@ <% timestamp = DateTime.parse(2.weeks.ago.to_s).to_time.strftime("%F %T") %> <% @email = Faker::Internet.email %> confirmed_email_user: - uid: "<%= @email %>" - email: "<%= @email %>" - provider: 'email' - confirmed_at: '<%= timestamp %>' - created_at: '<%= timestamp %>' - updated_at: '<%= timestamp %>' - encrypted_password: <%= User.new.send(:password_digest, 'secret123') %> + uid: "<%= @email %>" + email: "<%= @email %>" + nickname: 'stimpy' + provider: 'email' + confirmed_at: '<%= timestamp %>' + created_at: '<%= timestamp %>' + updated_at: '<%= timestamp %>' + encrypted_password: <%= User.new.send(:password_digest, 'secret123') %> + +<% @second_email = Faker::Internet.email %> +second_confirmed_email_user: + uid: "<%= @second_email %>" + email: "<%= @second_email %>" + nickname: 'stimpy2' + provider: 'email' + confirmed_at: '<%= timestamp %>' + created_at: '<%= timestamp %>' + updated_at: '<%= timestamp %>' + encrypted_password: <%= User.new.send(:password_digest, 'secret123') %> <% @fb_email = Faker::Internet.email %> duplicate_email_facebook_user: - uid: "<%= Faker::Number.number(10) %>" - email: "<%= @fb_email %>" - provider: 'facebook' - created_at: '<%= timestamp %>' - updated_at: '<%= timestamp %>' - confirmed_at: '<%= timestamp %>' - encrypted_password: <%= User.new.send(:password_digest, 'secret123') %> + uid: "<%= Faker::Number.number(10) %>" + email: "<%= @fb_email %>" + provider: 'facebook' + created_at: '<%= timestamp %>' + updated_at: '<%= timestamp %>' + confirmed_at: '<%= timestamp %>' + encrypted_password: <%= User.new.send(:password_digest, 'secret123') %> <% @unconfirmed_email = Faker::Internet.email %> unconfirmed_email_user: - uid: "<%= @unconfirmed_email %>" - email: "<%= @unconfirmed_email %>" - provider: 'email' - created_at: '<%= timestamp %>' - updated_at: '<%= timestamp %>' - encrypted_password: <%= User.new.send(:password_digest, 'secret123') %> + uid: "<%= @unconfirmed_email %>" + email: "<%= @unconfirmed_email %>" + provider: 'email' + created_at: '<%= timestamp %>' + updated_at: '<%= timestamp %>' + encrypted_password: <%= User.new.send(:password_digest, 'secret123') %> + confirmation_sent_at: '<%= timestamp %>' + +<% @recent_unconfirmed_email = Faker::Internet.email %> +<% recent_timestamp = DateTime.parse(1.day.ago.to_s).to_time.strftime("%F %T") %> +recent_unconfirmed_email_user: + uid: "<%= @recent_unconfirmed_email %>" + email: "<%= @recent_unconfirmed_email %>" + provider: 'email' + created_at: '<%= timestamp %>' + updated_at: '<%= timestamp %>' + encrypted_password: <%= User.new.send(:password_digest, 'secret123') %> + confirmation_sent_at: '<%= recent_timestamp %>' \ No newline at end of file diff --git a/test/lib/devise_token_auth/url_test.rb b/test/lib/devise_token_auth/url_test.rb new file mode 100644 index 000000000..6f75a4526 --- /dev/null +++ b/test/lib/devise_token_auth/url_test.rb @@ -0,0 +1,24 @@ +require 'test_helper' + +class DeviseTokenAuth::UrlTest < ActiveSupport::TestCase + describe "DeviseTokenAuth::Url#generate" do + test 'URI fragment should appear at the end of URL' do + params = {client_id: 123} + url = 'http://example.com#fragment' + assert_equal DeviseTokenAuth::Url.send(:generate, url, params), "http://example.com?client_id=123#fragment" + end + + describe 'with existing query params' do + test 'should preserve existing query params' do + url = 'http://example.com?a=1' + assert_equal DeviseTokenAuth::Url.send(:generate, url), "http://example.com?a=1" + end + + test 'should marge existing query params with new ones' do + params = {client_id: 123} + url = 'http://example.com?a=1' + assert_equal DeviseTokenAuth::Url.send(:generate, url, params), "http://example.com?a=1&client_id=123" + end + end + end +end diff --git a/test/lib/generators/devise_token_auth/install_generator_test.rb b/test/lib/generators/devise_token_auth/install_generator_test.rb index e9c280756..06059b4de 100644 --- a/test/lib/generators/devise_token_auth/install_generator_test.rb +++ b/test/lib/generators/devise_token_auth/install_generator_test.rb @@ -28,6 +28,10 @@ class InstallGeneratorTest < Rails::Generators::TestCase assert_migration 'db/migrate/devise_token_auth_create_users.rb' end + test 'migration file contains rails version' do + assert_migration 'db/migrate/devise_token_auth_create_users.rb', /#{Rails::VERSION::MAJOR}.#{Rails::VERSION::MINOR}/ + end + test 'subsequent runs raise no errors' do run_generator end @@ -44,14 +48,17 @@ class InstallGeneratorTest < Rails::Generators::TestCase # make dir if not exists FileUtils.mkdir_p(@dir) + # account for rails version 5 + active_record_needle = (Rails::VERSION::MAJOR == 5) ? 'ApplicationRecord' : 'ActiveRecord::Base' + @f = File.open(@fname, 'w') {|f| f.write <<-RUBY -class User < ActiveRecord::Base + class User < #{active_record_needle} - def whatever - puts 'whatever' - end -end + def whatever + puts 'whatever' + end + end RUBY } @@ -87,9 +94,9 @@ def whatever @f = File.open(@fname, 'w') {|f| f.write <<-RUBY -Rails.application.routes.draw do - patch '/chong', to: 'bong#index' -end + Rails.application.routes.draw do + patch '/chong', to: 'bong#index' + end RUBY } @@ -98,21 +105,21 @@ def whatever test 'route method is appended to routes file' do assert_file 'config/routes.rb' do |routes| - assert_match(/mount_devise_token_auth_for 'User', at: '\/auth'/, routes) + assert_match(/mount_devise_token_auth_for 'User', at: 'auth'/, routes) end end test 'subsequent runs do not modify file' do run_generator assert_file 'config/routes.rb' do |routes| - matches = routes.scan(/mount_devise_token_auth_for 'User', at: '\/auth'/m).size + matches = routes.scan(/mount_devise_token_auth_for 'User', at: 'auth'/m).size assert_equal 1, matches end end describe 'subsequent models' do before do - run_generator %w(Mang /mangs) + run_generator %w(Mang mangs) end test 'migration is created' do @@ -121,7 +128,7 @@ def whatever test 'route method is appended to routes file' do assert_file 'config/routes.rb' do |routes| - assert_match(/mount_devise_token_auth_for 'Mang', at: '\/mangs'/, routes) + assert_match(/mount_devise_token_auth_for 'Mang', at: 'mangs'/, routes) end end @@ -147,13 +154,11 @@ def whatever @f = File.open(@fname, 'w') {|f| f.write <<-RUBY -class ApplicationController < ActionController::Base - respond_to :json - - def whatever - 'whatever' - end -end + class ApplicationController < ActionController::Base + def whatever + 'whatever' + end + end RUBY } diff --git a/test/models/only_email_user_test.rb b/test/models/only_email_user_test.rb new file mode 100644 index 000000000..9575c9ec6 --- /dev/null +++ b/test/models/only_email_user_test.rb @@ -0,0 +1,35 @@ +require 'test_helper' + +class OnlyEmailUserTest < ActiveSupport::TestCase + describe OnlyEmailUser do + test 'trackable is disabled' do + refute OnlyEmailUser.method_defined?(:sign_in_count) + refute OnlyEmailUser.method_defined?(:current_sign_in_at) + refute OnlyEmailUser.method_defined?(:last_sign_in_at) + refute OnlyEmailUser.method_defined?(:current_sign_in_ip) + refute OnlyEmailUser.method_defined?(:last_sign_in_ip) + end + + test 'confirmable is disabled' do + refute OnlyEmailUser.method_defined?(:confirmation_token) + refute OnlyEmailUser.method_defined?(:confirmed_at) + refute OnlyEmailUser.method_defined?(:confirmation_sent_at) + refute OnlyEmailUser.method_defined?(:unconfirmed_email) + end + + test 'lockable is disabled' do + refute OnlyEmailUser.method_defined?(:failed_attempts) + refute OnlyEmailUser.method_defined?(:unlock_token) + refute OnlyEmailUser.method_defined?(:locked_at) + end + + test 'recoverable is disabled' do + refute OnlyEmailUser.method_defined?(:reset_password_token) + refute OnlyEmailUser.method_defined?(:reset_password_sent_at) + end + + test 'rememberable is disabled' do + refute OnlyEmailUser.method_defined?(:remember_created_at) + end + end +end diff --git a/test/models/user_test.rb b/test/models/user_test.rb index 09b2038eb..c06a6efbc 100644 --- a/test/models/user_test.rb +++ b/test/models/user_test.rb @@ -35,6 +35,28 @@ class UserTest < ActiveSupport::TestCase end end + describe 'email uniqueness' do + test 'model should not save if email is taken' do + provider = 'email' + + User.create( + email: @email, + provider: provider, + password: @password, + password_confirmation: @password + ) + + @resource.email = @email + @resource.provider = provider + @resource.password = @password + @resource.password_confirmation = @password + + refute @resource.save + assert @resource.errors.messages[:email] == [I18n.t('errors.messages.taken')] + assert @resource.errors.messages[:email].none? { |e| e =~ /translation missing/ } + end + end + describe 'oauth2 authentication' do test 'model should save even if email is blank' do @resource.provider = 'facebook' @@ -79,11 +101,24 @@ class UserTest < ActiveSupport::TestCase end test 'expired token was removed' do - refute @resource.tokens[@old_auth_headers['client']] + refute @resource.tokens[@old_auth_headers[:client]] end test 'current token was not removed' do - assert @resource.tokens[@new_auth_headers['client']] + assert @resource.tokens[@new_auth_headers["client"]] + end + end + + describe 'nil tokens are handled properly' do + before do + @resource = users(:confirmed_email_user) + @resource.skip_confirmation! + @resource.save! + end + + test 'tokens can be set to nil' do + @resource.tokens = nil + assert @resource.save end end end diff --git a/test/test_helper.rb b/test/test_helper.rb index da3a528b5..48e1b1435 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -1,13 +1,11 @@ -require "codeclimate-test-reporter" -#require 'simplecov' +require 'simplecov' #SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[ #SimpleCov::Formatter::HTMLFormatter, #CodeClimate::TestReporter::Formatter #] -#SimpleCov.start 'rails' -CodeClimate::TestReporter.start +SimpleCov.start 'rails' ENV["RAILS_ENV"] = "test" @@ -40,18 +38,22 @@ class ActiveSupport::TestCase # Add more helper methods to be used by all tests here... def age_token(user, client_id) - user.tokens[client_id]['updated_at'] = Time.now - (DeviseTokenAuth.batch_request_buffer_throttle + 10.seconds) - user.save! + if user.tokens[client_id] + user.tokens[client_id]['updated_at'] = Time.now - (DeviseTokenAuth.batch_request_buffer_throttle + 10.seconds) + user.save! + end end def expire_token(user, client_id) - user.tokens[client_id]['expiry'] = (Time.now - (DeviseTokenAuth.token_lifespan.to_f + 10.seconds)).to_i - user.save! + if user.tokens[client_id] + user.tokens[client_id]['expiry'] = (Time.now - (DeviseTokenAuth.token_lifespan.to_f + 10.seconds)).to_i + user.save! + end end end class ActionController::TestCase - include Devise::TestHelpers + include Devise::Test::ControllerHelpers setup do @routes = Dummy::Application.routes