setting up google OAuth in phoenix ▶▶▶

  • Its been almost a week or so learning the phoenix framework and elixir. I’ve gotten a bit of understanding on how the framework uses the MVC architecture to make building web applications easier, and how elixir’s functional programming capabilities make functional programing great again 😜
  • This post will focus on how to set up Google OAuth as a third-party login option for user authentication into the app built with the phoenix web framework.
    [ Assumption is that one already has a decent understanding of how both the language(elixir) and framework(phoenix) work.]
  • For every phoenix project created, a mix.exs file is generated. Inside this file is a function deps. This function contains all the dependencies that come already installed in the phoenix framework.

Step 1️⃣ Add Ueberauth and Google Dependencies

  • We want to add a new dependency that allows for 3rd party authentication. For our app we will use ueberauth :here is the Github repo. Also we add the specific 3rd party auth_source to use, in this case we using google oauth. The deps function now has two dependencies added, as shown below in lines 14 and 15
  • Also, inside the same mix.exs file is another function, application that executes everytime the phoenix app starts. We have add the two dependencies as well.
  • The application function now looks like this, below

Step 2️⃣ Run command to install the dependencies

  • After adding these dependencies, we then run the command in our terminal that executes and installs these dependencies in our app.
$ mix deps.get

which should show the entire list of dependencies including the ones we just added.

Step 3️⃣ Update config.exs file

  • Now, we navigate to the config.exs file where we need to add this line of code at the end to configure the “providers” . providers are the 3rd party login apps, like Google, Github or Facebook …etc

Step 4️⃣ Create a google client ID

  • Use this link to create a google api project, that will generate two values [client_id and client_secret] that we need for our phoenix app.
  • Add those two values to the config.exs file as below
updated config file with ueberauth, client_id and client_secret
  • Once the above configuration steps are all done, now we can add code that shows how to create new controller that handles authentication, and also appropriate routes for signing in and out of the application.

Next Steps

Step 5️⃣ Add routes for signing in.

  • Inside the router.exs define a new “scope” that handles requests starting with this path/auth. Add the routes for sign in as below.
  • line 6. specifies a GET request with;
    /:provider will be a google, or any other 3rd party login option.
    AuthController is name of controller we will create.
    :request is a pre-defined function.
  • line 7. specifies a GET request with;
    /:provider/callback for redirecting from the google api with user profile.
    :callback is a function that we will implement.

Step 6️⃣ Create user model and add database migrations.

  • Assumption is, PostgreSql is already installed as a database of use. Phoenix uses Ecto for migrations and Repo namespace for communication to the PostgreSql database.
  • Add user.ex as a model in the models folder. Code below defines a User module with schema that specifies the type of each field in the database.
  • Run this command that adds a migration file to your project.
$ mix ecto.gen.migrations add_users
  • This generates a migration file under the /priv/repo/migrationsfolder. this file an empty function change(). Add the following code to that empty function that creates a table with its columns specified as in the schema.
  • Finally run this command to create the actual table in the postgres database.
$ mix ecto.migrate

Step 7️⃣ Create Controller for handling Authentication.

  • Inside the controllers folder, create a new controller file, for example, auth_controller.exs . add logic for the callback function, and sign_in functionality. below is code that handles a user logging in with a 3rd party option, and redirection to index page of our app, plus adding user info pulled for google api into our db.
  • line 2: we use pattern matching to extract the auth object from the conn parameter.
  • line 3: still using pattern matching to extract the user_params from the auth object. The user_params include the user_token, email, and provider.
  • line 4: creates changeset object that now contains the the values we need.
  • line 6: we then pass that changeset object to the signin function.
  • The signin() checks to see if that user exists in the database, if not it inserts the new user into the database, or else it just logs them back into the app.

Step 8️⃣ Create plug that checks user session:

  • Once the user has been signed-in, we need to find a way to keep track of the user session. We accomplish this buy creating a plug. a plug is basically a function or module that gets a conn object, makes a tiny modification to this object and then returns a “modified” conn object.
  • In our case, we will create a module plug, since it will be used in different sections of our code where we would prefer to know if a user is logged in.
    Create a new folder plugs inside of the controller directory. then create a file inside the plugs folder. our module plug is user.ex defined below. (check # comments in code for each line explanation)
a module plug must contain two functions: ie init() and call()
  • Now, inside the router.ex file, add this module plug to the list of pipeline plugs that get executed wherever a request is sent from a user. as seen below on line 10 (line 10 contains plug we just created)

Step 9️⃣ Add sign-in button on layout_view page.

Since the sign_in and sign_out feature have to be on every page, we should put the html/css design in the generic layout page. this code below adds the link for sign in and also shows with controller function to access whenever a user clicks the sign-in link.

  • line 4: checks the conn object that contains the user details, and checks if it exits, and if so, it displays the option for the to signout.
  • line 10: is for when the user is not logged(meaning the @conn.assigns[:user] returns nil), then show them the sign in button.

Step 🔟 Add functionality for signing out

  • This should easier since we already have the auth_controller, and the logic for handling sessions for a user when signed in.
  • Just add this sign_out function to the auth_controller
  • line 5: sets the drop key to true, thereby closing the session for user
  • line 6: then redirects user to the index function of the controller with developer_path

🙌 END 🙌

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store