DEV Community

Guide to devise_token_auth: Simple Authentication in Rails API

Risa Fujii on February 09, 2019

I wanted to create an authentication system for my Rails API, but one thing about APIs (with no client) is that you can't use sessions or cookies f...
Collapse
 
masroorhussainv profile image
Masroor Hussain

that extend Devise::Models is on point and needs to be done for this to work. Thanks!

Collapse
 
risafj profile image
Risa Fujii

Happy to hear it! :D

Collapse
 
mirmayne profile image
Info Comment hidden by post author - thread only accessible via permalink
Daveyon Mayne 😻

Gonna add this as I'm sure many will find this useful. ✊🏽

Rails.application.config.middleware.insert_before 0, Rack::Cors do
    [...]
      expose: ['access-token', 'uid', 'client'],
    [...]
  end
end
Enter fullscreen mode Exit fullscreen mode
Collapse
 
masroorhussainv profile image
Masroor Hussain

I had to do
require 'devise_token_auth' in the routes.rb file, otherwise I was getting this error:
NoMethodError (undefined method `mount_devise_token_auth_for' for #ActionDispatch::Routing::Mapper:0x...)

Github issue here

Collapse
 
risafj profile image
Risa Fujii

Thanks for reading and for the comment! I'll add a note in the post :)

Collapse
 
johanbaaij profile image
Johan Baaij

Thanks! devise_token_auth works great for me and I found your other article about testing useful as well.

But :)! What if you do need to store some session data? I'm trying to authenticate with the Discogs API which involves generating a request token, going to their website to authorize, which then redirects you to a callback route on the Rails API. What's the correct way to persist that request token in between those two requests?

Is it bad practice to just store it in a DB column for the user?

Collapse
 
risafj profile image
Risa Fujii • Edited

Hi! Thanks for reading, and I’m happy to hear it helped 😄
Please take my ideas below with a grain of salt, since I don’t know your specific use case and I haven't used the Discogs API.

generating a request token, going to their website to authorize, which then redirects you to a callback route on the Rails API.

I’m guessing from this description that your app has a browser client? In that case, you should be able to use session storage normally and store it like this: session[:discogs_token] = <the request token>
If you used Rails’s API mode when initializing your project (the --api flag), sessions won’t be available to you by default so it looks like you’ll have to configure a few things: stackoverflow.com/q/15342710/11249670

On the other hand, if you're supposed to store the token for a long time (longer than the session), then storing it in the DB sounds like a good idea.
For example, in a different blog post that I linked below, I talk about refresh tokens, which are supposed to be reused in every session.
In this blog post's case, I store normal access tokens in the session, and refresh tokens in the DB.

Hope this helps somewhat!

Collapse
 
johanbaaij profile image
Johan Baaij

Thanks for taking the time to get back to me. My API is consumed by a Vue.js client (using vue-auth). I've tried all the different middlewares and setting api mode to false but always see my session contents emptied.

Ah well! For now I'm saving the request_token in my DB until the callback is called. And yes, the access_token is needed for using the API once authorized.

Thread Thread
 
risafj profile image
Risa Fujii • Edited

No problem, sorry I can't be more helpful. If your issue is that you can't use session at all with your configuration (not just for devise_token_auth), it might be a good question for Stack Overflow. Best of luck!

Collapse
 
leesmith profile image
Lee Smith 🍻

You actually can use session cookies for API authentication...as long as the API client is a web browser. Given that caveat, I thought this approach was interesting because it takes advantage of the battle-tested CSRF protection already built into Rails.

pragmaticstudio.com/tutorials/rail...

Collapse
 
risafj profile image
Risa Fujii

Thank you for your comment! Perhaps I should've specified - I meant Rails API with no front-end when I was talking about not being able to use sessions.

Collapse
 
mirmayne profile image
Daveyon Mayne 😻

It's nice to let readers know that Devise gem must be installed first 🙃

Collapse
 
risafj profile image
Risa Fujii

Hi, thanks for the comment. I imagine that if you add devise_token_auth to your Gemfile and run bundle, the Devise gem would be added as a dependency (so you don't need to install Devise separately). Is this not the case?

Collapse
 
mirmayne profile image
Daveyon Mayne 😻

Hi. It's not the case with Rails 6 API in my case. I do not know why. My Gemfile:

# Authentication
gem 'devise'
gem 'devise_token_auth'
Thread Thread
 
risafj profile image
Risa Fujii • Edited

Happy new year :)
Hmm, that's strange. Out of curiosity, I created a new repo and followed my own tutorial. I had to make some updates in the article to compensate for changes made in devise, but I didn't have to include the devise gem in the Gemfile. Feel free to check out the project: github.com/risafj/demo-for-devise-...

Thread Thread
 
mirmayne profile image
Daveyon Mayne 😻

I had a fresh copy of the api installed using ruby 2.5.0. If I remove the devise gem, the auth breaks lol I know this is weird. I'll upgrade both ruby and rails and try again. But yea, I believe something weird is happening with my setup.

Thanks.

Thread Thread
 
mirmayne profile image
Daveyon Mayne 😻

To update. Another fresh installation with ruby 2.7.0 and Rails 6.0.2.1 and all is well (production). Weird, I know. 😅

Thread Thread
 
risafj profile image
Risa Fujii

Hmm... we may never find out why 😂 Glad it’s working now though! Thanks for the update!

Collapse
 
fabiantorresm profile image
Fabian Torres M

Hello everyone, I have two questions, I hope you can help me,

1.- How do I connect social login?
2.- How do I use the password recovery module from a mobile?

Can you help me with any suggestion?

I already saw the documentation, but it makes me confused especially in recovering password

Thank you

Collapse
 
dallasgoldswain profile image
Dallas Goldswain

Awesome post! Exactly what I was looking for.

Collapse
 
risafj profile image
Risa Fujii

Thanks for the comment, happy to hear it helped!

Collapse
 
babarali539 profile image
Babar Ali

Thanks for the post.. But I am just wondering about how we can implement forgot password using this as I am unable to understand whatever is written in the documentation about this flow. That would be great if you add a post for that too.

Collapse
 
sangeeky profile image
Santiago Pinchao

Thanks for the article! This file
config/initializers/devise_token_auth.rb

Is important too, for example with the time life of a token

Collapse
 
nelcifranmagalhaes profile image
Nelcifran

Nice, this help me today...Thanks

Collapse
 
risafj profile image
Risa Fujii

Hi, happy to hear it! :)

Collapse
 
rafaso profile image
Rafael Oliveira

Hi!
Nice post, only add below statement: "extends Devise::Models" to begin User's model, after devise_token_auth install. This to rails version 6.

something else is ok :)

Collapse
 
risafj profile image
Risa Fujii

Just saw this - thank you, I will add it as a note in the post!

Collapse
 
nodefiend profile image
chowderhead

Nailed it ! thanks for your work!

Collapse
 
nodefiend profile image
chowderhead

this is a very difficult topic.. thanks for covering it for us noobies

Collapse
 
risafj profile image
Risa Fujii

Thanks for the comment! Happy to hear it helped :)

Collapse
 
jesyontop01 profile image
Adelaja Jeremiah Anuoluwapo

Hi. Thanks for the tutorial, but I have a little challenge customizing the session controller .... I will be glad if I can get a little assistance in that regard...
Jerry A.
jesyontop01@gmail.com

Collapse
 
risafj profile image
Risa Fujii • Edited

Hi, what kind of issue are you having? You'll probably have a better time asking on the devise_token_auth's Github issues or Stack Overflow, but maybe I could take a look!

Collapse
 
abeyanc3 profile image
Abeyanc3

I cannot create user. Am I supposed to use devise for registration instead?
However, creating user from the console then logging in works fine.

Collapse
 
risafj profile image
Risa Fujii

Am I supposed to use devise for registration instead?

No, you should be able to use device_token_auth. Are you getting some kind of error message when you try to create a user by hitting the endpoint?

Collapse
 
abeyanc3 profile image
Abeyanc3

Sorry, my bad. Fixed it.

Great tutorial! Works fine with Rails 6.1.4 and Ruby 3.0.1

Collapse
 
krlosgilson profile image
Carlos Andrade

Once logged in, how do I make requests using the generated token? For ex: A GET request: localhost:3000/clients

Collapse
 
risafj profile image
Risa Fujii

As written in the article - you set the token in your request headers!

Some comments have been hidden by the post's author - find out more