setting up google OAuth in phoenix ▶▶▶
5 min readJul 26, 2018
- 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 functiondeps
. 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. Thedeps
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
andclient_secret
] that we need for our phoenix app. - Add those two values to the
config.exs
file as below
- 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 andRepo
namespace for communication to the PostgreSql database. - Add
user.ex
as a model in themodels
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/migrations
folder. this file an empty functionchange().
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 theconn
parameter. - line 3: still using pattern matching to extract the
user_params
from theauth
object. Theuser_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 folderplugs
inside of thecontroller
directory. then create a file inside theplugs
folder. our module plug isuser.ex
defined below. (check # comments in code for each line explanation)
- 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 🙌