Mobile app authentication with rails
Here is some music to turn on while reading
When we’d like to have auth in mobile app we can do it in various ways nowdays. But what if we want to use rails to make it happen? Because thats just what we do :-D
Imagine if we can just use all the things rails offers somehow magically with minimal modification. All that good stuff somehow. There must be a way. Can we somehow just put user form in our mobile app and use rails sessions et al.
What if when rails issues a cookie we convert it to json and attach it to json response so that our app gets the cookie in easy way? That would work. We take cookie from json response and send it back. Sounds like it makes sense.
Lets intercept all requests that come out of rails and if its json request and cookie is being set lets take it from headers and put it in json body
class RequestMiddlewhare def initialize(app) @app = app end def call(env) req = Rack::Request.new(env) status, headers, body = @app.call(env) if env["PATH_INFO"].match("json") && !env["REQUEST_METHOD"].match("OPTION") body[0] = JSON.parse(body[0]).merge({"Set-Cookie"=>headers["Set-Cookie"]}).to_json end [status, headers, body] end end config.middleware.insert_before 0, RequestMiddlewhare
Now how do we send it back? Usually in desktop how it works is that browser includes cookie automagically. We need to send it some other way. What if we include a paramter in each request we want checked. That sounds legitimate. Lets call that parameter cookie.
If we again intercept every request comming into rails and if we spot parameter cookie. We’ll make it so as if browser sent cookie. We will fill environment variable HTTP_COOKIE with content from request parameter. That should do the trick like so.
class RequestMiddlewhare def initialize(app) @app = app end def call(env) req = Rack::Request.new(env) cookie = req.params[:cookie] || req.params["cookie"] if cookie cookie = Base64.decode64(cookie) #env["HTTP_COOKIE"] = Rack::Request.new(env).params[:cookie] env["HTTP_COOKIE"] = cookie end status, headers, body = @app.call(env) if env["PATH_INFO"].match("json") && !env["REQUEST_METHOD"].match("OPTION") body[0] = JSON.parse(body[0]).merge({"Set-Cookie"=>headers["Set-Cookie"]}).to_json end [status, headers, body] end end config.middleware.insert_before 0, RequestMiddlewhare
Now we have full power of rails sessions for a mobile app.
You have to put above code in
application.rb
like so
module MyApp class Application < Rails::Application class RequestMiddlewhare def initialize(app) @app = app end def call(env) req = Rack::Request.new(env) cookie = req.params[:cookie] || req.params["cookie"] if cookie cookie = Base64.decode64(cookie) #env["HTTP_COOKIE"] = Rack::Request.new(env).params[:cookie] env["HTTP_COOKIE"] = cookie end status, headers, body = @app.call(env) if env["PATH_INFO"].match("json") && !env["REQUEST_METHOD"].match("OPTION") body[0] = JSON.parse(body[0]).merge({"Set-Cookie"=>headers["Set-Cookie"]}).to_json end [status, headers, body] end end config.middleware.insert_before 0, RequestMiddlewhare end end
Cheers. You can copy freely if you need licence lets say it has MIT licence.
You might want to disable cors and put session tracking inside of cookie too like so So that you can call rails from mobile app.
module MyTestApp class Application < Rails::Application # Initialize configuration defaults for originally generated Rails version. config.middleware.insert_before 0, Rack::Cors do allow do origins do |source, env| true end resource '*', :headers => :any, :methods => [:get, :post, :options], :credentials => true end end class RequestMiddlewhare def initialize(app) @app = app end def call(env) req = Rack::Request.new(env) cookie = req.params[:cookie] || req.params["cookie"] if cookie cookie = Base64.decode64(cookie) #env["HTTP_COOKIE"] = Rack::Request.new(env).params[:cookie] env["HTTP_COOKIE"] = cookie end status, headers, body = @app.call(env) if env["PATH_INFO"].match("json") && !env["REQUEST_METHOD"].match("OPTION") body[0] = JSON.parse(body[0]).merge({"Set-Cookie"=>headers["Set-Cookie"]}).to_json end [status, headers, body] end end config.middleware.insert_before 0, RequestMiddlewhare config.load_defaults 6.0 config.allow_forgery_protection=false config.session_store :cookie_store, key: '_interslice_session' config.middleware.use ActionDispatch::Cookies # Required for all session management config.middleware.use ActionDispatch::Session::CookieStore, config.session_options # Settings in config/environments/* take precedence over those specified here. # Application configuration can go into files in config/initializers # -- all .rb files in that directory are automatically loaded after loading # the framework and any gems in your application. end end