Home > SM Geeking, Technology > Ask not for whom the app logs-in, it logs-in as thee …

Ask not for whom the app logs-in, it logs-in as thee …

September 8, 2018

With this installment’s title I must extend apologies to John Donne, though had he lived today I’m sure the great metaphysical poet would have been concerned with more inevitable eventualities than death … like the inevitable need to go online and once there, to login to something.

Logging in and getting a personalized experience with our apps is a universal expectation, not to mention in lots of cases a logical requirement. Back in the day we’d blithely enter our email address yet again, and use the same ‘ol password, just to register with a site we’ll probably use only 1 time in our lives. Well, those days are gone. Not only are users weary of all these separate logins, I as a developer want to minimize the effort I spend on basic stuff, so I can save it for the specific features of my app. So what I decided to do is use OAuth, the standard that allows sites to cooperate on user-identity. In vastly-condensed summary: OAuth allows different applications to share identity information based on shared keys. When you got to a site and see “Login with Facebook”, and click that, here’s what happens:

  • The site formats a link to the identity provide – in this case Facebook – that includes a signature. The signature is a long string of data created by processing some input with a secret key.
  • The user’s browser is sent to page hosted by Facebook. Behind the scenes Facebook checks the signature, using its own copy of the secret key. Then it asks you, “App such-and-such wants access t your email address, etc. You good with that?”
  • Assuming you click “Yes”, Facebook re-directs back top the original site, including its own signed and encrypted data. because that data was  created, once again,  with the same secret key, the app can read it and find your user-name, along with whatever other things you may have approved.

That’s the theory. Now in practice I want to have such a “Login with Facebook:” button on my site. To do that I do what most developers do: Google “rails facebook oauth login”. As expected the 1st page of results had 3-4 tutorials on how to do just that.

What’s the next step? if I was at work I’d most likely read through the candidate articles, pick the best one, then write out the requirements and steps in a new document, then do that. At home, well, I can only say I have a more carefree attitude. I started following the steps of one tutorial that was based on Omniauth and React-Rails (more on React later) but decided after a hour or so that was too much UX work than I wanted to do just now. So I stopped that path and started a different route using Devise, a Rails-based framework that is a largely pre-made authentication system.

Then the hackery began. I removed the original routes I had added with the 1st version,  then used the Devise utilities to generate new ones. if you’re not familiar with Rails, its ‘generator’ facility is used all the time to create config files, stub files, and much more. For example:

rails generate device:install

will create a complete devise configuration, prompting you for settings along the way. Alas, I couldn’t do that all-in-1 step because of the 1st attempt stuff I had in place, so I set out doing it piecemeal.

In the end it all worked, but the process wasn’t pretty. I did have to spend about an hour trying to resolve an error, where I had only this log text to go on:

F, [6 #8279] FATAL — : [c6e010f3-c1b9-4675-90d6-9bdaeb42c1b5] ArgumentError (wrong number of arguments (given 0, expected 1)):
F, [7 #8279] FATAL — : [c6e010f3-c1b9-4675-90d6-9bdaeb42c1b5] app/models/user.rb:19:in `from_omniauth'[ 

This was one of those that looks specific to the problem – line 19 in file user.rb is messed up, right? – but actually did not explain anything. I tried different things, to no avail. Finally I brute force rescued the exception and printed the “real” stack trace, which was:

F, [5 #8280] ERROR — : [7120f455-99a1-4427-922c-053742c6194d] wrong number of arguments (given 0, expected 1)
F, [6 #8280] ERROR — : [7120f455-99a1-4427-922c-053742c6194d] /app/vendor/bundle/ruby/2.5.0/gems/devise-4.5.0/lib/devise/models/database_authenticatable.rb:166:in `password_digest’/

So the crash wasn’t in my code, it was in the Devise framework. The problem turned out to be this: I created my original user-model to use a Rails option has_secure_password. This requires a database column and model-attribute password_digest. However the Devise framework adds its *own* method named password_digest that takes 1 argument. The fix: remove has_secure_password and the password_digest column.

So there it is. If you’re of a mind you can Try the FB Login Demo here.

My closing thought … software frameworks, like cars, are things that people build and because of that you’d think we know everything about them. Well, we don’t. The picture below captures this thought:

mechanic

Next time: SM Geeking takes on user-interface. Systems architect that I am, comedy is guaranteed. Don’t miss it!

Categories: SM Geeking, Technology
%d bloggers like this: