We use Omniauth gem for OAuth2.0 at Public Lab to sign up/log in via different providers. OmniAuth is a library that standardizes multi-provider authentication for web applications. To enable omniauth work, we use omniauth gem.
Multiparty Authentication system currently has 4 providers, namely:
- Github: Using the omniauth-github gem for OAuth.
- Google: Using the omniauth-google-oauth2 gem for OAuth.
- Twitter: Using the omniauth-twitter gem for OAuth.
- Facebook: Using the omniauth-facebook gem for OAuth.
To sign up or log in via a provider or to link a provider, go to https://publiclab.org/auth/:provider. Sign in through the provider with the desired email address and password. Then the user will be redirected to https://publiclab.org/auth/:provider/callback. Authentication hash is available in the callback. It can be accessed by request.env['omniauth.auth']
for any provider. Now the user signs up, logs in or links their providers' accounts to their Public Lab account.
Linking of any account through providers is based on the following cases:
- If the client is signed in and does not have any account of the same provider through which they are trying to connect to their Public Lab account, then the provider will be linked to their account.
- If the client is signed in and has an account linked to their Public Lab account of the same provider through which they are trying to connect, then he/she is notified that the linking can't be done.
- If the client is not signed in and has the provider already linked to their Public Lab account, then the client logs in successfully.
- If the client is not signed in and has an account with same email address as that given by the provider through which they are trying to connect, then their existing account is linked to the provider's account and they're signed in to Public Lab.
- If the client is not signed in and has no account with the same email address as that given by the provider through which they are trying to sign in, then a new account is created. After a new account is created, the provider is linked to that new Public Lab account and the client is notified by email to change their password.
For a new account creation, email_prefix
i.e. the part of email before @
symbol, is used as username. In case there exists a user with the same username then randomly generated hexadecimal code is appended to the email_prefix. Then this email_prefix is used as username.
Corresponding code is present in https://github.com/publiclab/plots2/blob/master/app/models/user.rb and https://github.com/publiclab/plots2/blob/master/app/controllers/user_sessions_controller.rb.
- Usertags are used to store the provider and the uid for authentication. The client may delete their usertag via the profile page in order to delete the corresponding provider from their account.
The functionality of this system is demonstrated on https://publiclab.org/oauth.
Developers can create a developer's app for OAuth. Each app created has an app_id and an app_secret.
- For creating Facebook app go to http://developers.facebook.com/
- For creating Twitter app go to https://apps.twitter.com/app/new
- For creating Github app go to https://github.com/settings/applications/new
- For creating Google app go to https://console.developers.google.com/apis/library And then create an app. Search for the app_id and app_secret present in your app.
As to the environment variables, you can insert them at run time locally by doing:
OAUTH_GOOGLE_APP_KEY=xxxxxxxx passenger start
Or, you can put it in a file like environment.sh
which is like:
OAUTH_GOOGLE_APP_KEY=xxxxxxxx
and do:
source environment.sh && passenger start
Or, write them in config/application.yml file
Add the app_id and app_secret in the Jenkins and containers/docker*.yml files in the production. They are accessed by ENV["OAUTH_GITHUB_APP_KEY"], ENV["OAUTH_GITHUB_APP_SECRET"] etc inside the (config/initializers/omniauth.rb)[https://github.com/publiclab/plots2/blob/master/config/initializers/omniauth.rb]
For improving UI, login and signup modals were created. The code for the login and signup modals is https://github.com/publiclab/plots2/blob/master/app/views/layouts/_header.html.erb#L176-L266.
A custom JavaScript class named 'requireLogin' is inserted at the locations where login modal needs to be rendered.
For example, it can be implemented in a button with the button class as btn btn-default requireLogin
.
- OAUTH_GOOGLE_APP_KEY: It contains app_id of the google developer's app created
- OAUTH_GOOGLE_APP_SECRET: It contains app_secret of the google developer's app created
- OAUTH_GITHUB_APP_KEY: It contains app_id of the github developer's app created
- OAUTH_GITHUB_APP_SECRET: It contains app_secret of the github developer's app created
- OAUTH_FACEBOOK_APP_KEY: It contains app_id of the facebook developer's app created
- OAUTH_FACEBOOK_APP_SECRET: It contains app_secret of the facebook developer's app created
- OAUTH_TWITTER_APP_KEY: It contains app_id of the twitter developer's app created
- OAUTH_TWITTER_APP_SECRET: It contains app_secret of the twitter developer's app created
OAuth can be tested by including the following in config/environments/test.rb
OmniAuth.config.test_mode = true
OmniAuth.config.mock_auth[:provider] = OmniAuth::AuthHash.new({
'provider' => 'name_of_provider',
'uid' => '1357908642',
'info' => {
'name' => 'user name',
'email' => 'user.email.address@xyz.com'
}
})
This is a way of storing the hash returned by the OAuth service.
Tester can then use these values by
request.env['omniauth.auth'] = OmniAuth.config.mock_auth[:google_oauth2_2]
Let us define the password_checker field for authentication system A user creates an account by the legacy authentication system 0 Facebook 1 Github 2 Google 3 Twitter 4
Password is set up by the client is denoted by zero. Password not set up is denoted by non zero field. If a user who is not having password field set up tries to log in with password and username then they will be noticed with an error message to reset their password. Upon setting up password, password_checker field is set to zero.