Git Product home page Git Product logo

elixir-auth-google-demo's Introduction

elixir-auth-google demo

A basic example of using Google Auth in a Phoenix App.

GitHub Workflow Status codecov.io Hex.pm contributions welcome HitCount

Try it: https://elixir-google-auth-demo.fly.dev

Why? 🤷

As developers we are always learning new things. When we learn, we love having detailed docs and examples that explain exactly how to get up-and-running. We write examples because we want them ourselves, if you find them useful, please ⭐ the repo to let us know.

What? 💭

This project is intended as a barebones demonstration of using elixir-auth-google to add support for "Sign-in with Google" to any Phoenix Application.

Who? 👥

This demos is intended for people of all Elixir/Phoenix skill levels. Anyone who wants the "Sign-in with Google" functionality without the extra steps to configure a whole auth framework.

Following all the steps in this example should take around 10 minutes. However if you get stuck, please don't suffer in silence! Get help by opening an issue: https://github.com/dwyl/elixir-auth-google/issues

How? 💻

This example follows the step-by-instructions in the docs github.com/dwyl/elixir-auth-google

0. Create a New Phoenix App

Create a new project if you don't already have one:

If you're adding elixir_auth_google to an existing app, you can skip this step.
Just make sure your app is in a known working state before proceeding
.

mix phx.new app  -no-assets --no-ecto --no-dashboard --no-gettext --no-live --no-mailer

We don't need a static asset compilation, database, dashboard, translation, LiveView or email for this demo. But we know they work fine because we are using this package in our App in production.

If prompted to install dependencies Fetch and install dependencies? [Yn] Type y and hit the [Enter] key to install.

You should see something like this:

* running mix deps.get

Make sure that everything works before proceeding:

mix test

You should see:

Generated app app
...

Finished in 0.02 seconds
3 tests, 0 failures

The default tests pass and you know phoenix is compiling.

Run the web application:

mix phx.server

and visit the endpoint in your web browser: http://localhost:4000/ phoenix-default-home

1. Add the elixir_auth_google package to mix.exs 📦

Open your mix.exs file and add the following line to your deps list:

def deps do
  [
    {:elixir_auth_google, "~> 1.6.5"}
  ]
end

Run the mix deps.get command to download.

2. Create the Google APIs Application OAuth2 Credentials ✨

Create your Google App and download the API keys by follow the instructions in: /create-google-app-guide.md

By the end of this step you should have these two environment variables defined:

GOOGLE_CLIENT_ID=631770888008-6n0oruvsm16kbkqg6u76p5cv5kfkcekt.apps.googleusercontent.com
GOOGLE_CLIENT_SECRET=MHxv6-RGF5nheXnxh1b0LNDq

⚠️ Don't worry, these keys aren't valid. They are just here for illustration purposes.

3. Create 2 New Files ➕

We need to create two files in order to handle the requests to the Google Auth API and display data to people using our app.

3.1 Create a GoogleAuthController in your Project

In order to process and display the data returned by the Google OAuth2 API, we need to create a new controller.

Create a new file called lib/app_web/controllers/google_auth_controller.ex

and add the following code:

defmodule AppWeb.GoogleAuthController do
  use AppWeb, :controller

  @doc """
  `index/2` handles the callback from Google Auth API redirect.
  """
  def index(conn, %{"code" => code}) do
    {:ok, token} = ElixirAuthGoogle.get_token(code, conn)
    {:ok, profile} = ElixirAuthGoogle.get_user_profile(token.access_token)
    conn
    |> put_view(AppWeb.PageView)
    |> render(:welcome, profile: profile)
  end
end

This code does 3 things:

  • Create a one-time auth token based on the response code sent by Google after the person authenticates.
  • Request the person's profile data from Google based on the access_token
  • Render a :welcome view displaying some profile data to confirm that login with Google was successful.

Note: we are placing the welcome.html.eex template in the template/page directory to save having to create any more directories and view files. You are free to organise your code however you prefer.

3.2 Create welcome template 📝

Create a new file with the following path: lib/app_web/templates/page/welcome.html.eex

And type (or paste) the following code in it:

<section class="phx-hero">
  <h1> Welcome <%= @profile.given_name %>!
  <img width="32px" src="<%= @profile.picture %>" />
  </h1>
  <p> You are <strong>signed in</strong>
    with your <strong>Google Account</strong> <br />
    <strong style="color:teal;"><%= @profile.email %></strong>
  <p/>
</section>

The Google Auth API get_profile request returns profile data in the following format:

%{
  email: "[email protected]",
  email_verified: true,
  family_name: "Co",
  given_name: "Nelson",
  locale: "en",
  name: "Nelson Co",
  picture: "https://lh3.googleusercontent.com/a-/AAuE7mApnYb260YC1JY7",
  sub: "940732358705212133793"
}

You can use this data however you see fit. (obviously treat it with respect, only store what you need and keep it secure)

4. Add the /auth/google/callback to router.ex

Open your lib/app_web/router.ex file and locate the section that looks like scope "/", AppWeb do

Add the following line:

get "/auth/google/callback", GoogleAuthController, :index

That will direct the API request response to the GoogleAuthController :index function we defined above.

5. Update PageController.index

In order to display the "Sign-in with Google" button in the UI, we need to generate the URL for the button in the relevant controller, and pass it to the template.

Open the lib/app_web/controllers/page_controller.ex file and update the index function:

From:

def index(conn, _params) do
  render(conn, "index.html")
end

To:

def index(conn, _params) do
  oauth_google_url = ElixirAuthGoogle.generate_oauth_url(conn)
  render(conn, "index.html",[oauth_google_url: oauth_google_url])
end

5.1 Update the page/index.html.eex Template

Open the /lib/app_web/templates/page/index.html.eex file and type the following code:

<section class="phx-hero">
  <h1>Welcome to Awesome App!</h1>
  <p>To get started, login to your Google Account: <p>
  <a href={@oauth_google_url}>
    <img src="https://i.imgur.com/Kagbzkq.png" alt="Sign in with Google" />
  </a>
</section>

The home page of the app now has a big "Sign in with Google" button:

sign-in-button

Once the person completes their authentication with Google, they should see the following welcome message:

welcome

Testing

To test the GoogleAuthController, create a new file with the path: test/app_web/controllers/google_auth_controller_test.exs

And add the following code:

defmodule AppWeb.GoogleAuthControllerTest do
  use AppWeb.ConnCase

  test "google_handler/2 for google auth callback", %{conn: conn} do
    conn = get(conn, "/auth/google/callback", %{code: "234"})
    assert html_response(conn, 200) =~ "[email protected]"
  end
end

Next, open the config/test.exs file and add the following lines:

config :elixir_auth_google,
  client_id: "631770888008-6n0oruvsm16kbkqg6u76p5cv5kfkcekt.apps.googleusercontent.com",
  client_secret: "MHxv6-RGF5nheXnxh1b0LNDq",
  httpoison_mock: true

These lines of config ensure that the HTTPoisonMock version of elixir_auth_google will be used when MIX_ENV=test. So the code will be covered in tests but the HTTP requests are mocked.

When you run the tests, they should pass:

mix test

....
Finished in 0.06 seconds (0.03s async, 0.03s sync)
4 tests, 0 failures

Randomized with seed 847344

And if you run the tests with coverage tracking, e.g:

mix c

You should see:

Compiling 3 files (.ex)
Generated app app
....
Finished in 0.05 seconds (0.03s async, 0.02s sync)
4 tests, 0 failures

Randomized with seed 44511
----------------
COV    FILE                                        LINES RELEVANT   MISSED
100.0% lib/app_web/controllers/google_auth_cont       15        3        0
100.0% lib/app_web/controllers/page_controller.        8        2        0
100.0% lib/app_web/router.ex                          18        3        0
100.0% lib/app_web/views/error_view.ex                16        1        0
[TOTAL] 100.0%
----------------

And with that, we're done with the demo. ✅

If you still have questions, please open an issue: dwyl/elixir-auth-google/issues

Deployment to Fly.io

Deploying this demo app to Fly.io is very easy. Simply follow the official Elixir Getting Started guide: fly.io/docs/elixir/getting-started

fly launch

Speed through the prompts to create the App and then add the add the 3 required environment variables:

fly secrets set GOOGLE_CLIENT_ID=868803175225-65qvrdfvi053p227mt.apps.googleusercontent.com
fly secrets set GOOGLE_CLIENT_SECRET=GOCSPX-QoIsUcqQ1dYN5XhHCe
fly secrets set SECRET_KEY_BASE=q1qDhNOFQk45a1Fb/eaSyWb77sd2a8jQ109oAwLkje7GDOBTBf53lgoSKHzAsEc1

Note: none of these keys are valid. They are just for illustration purposes. Follow the instructions: dwyl/elixir-auth-google/blob/main/create-google-app-guide.md to get your Google App keys.

Refer to the Dockerfile and fly.toml in this demo project if you need an example.

elixir-google-auth-demo.fly.dev

elixir-google-auth-demo.fly.dev

Recommended reading: "Deploying with Releases" hexdocs.pm/phoenix/releases.html

For Continuous Deployment to Fly.io, read: fly.io/docs/app-guides/continuous-deployment-with-github-actions

elixir-auth-google-demo's People

Contributors

dependabot[bot] avatar iteles avatar ndrean avatar nelsonic avatar simonlab avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

Forkers

vicmaster ndrean

elixir-auth-google-demo's Issues

MatchError Google OAuth Fails due to TLS Version in Cowboy 🤦

Annoyingly, while I'm trying to to update the dependency on auth_plug in auth: dwyl/auth#83 (comment)
I'm seeing this error:

no match of right hand side value: {:error, %HTTPoison.Error{id: nil, reason: {:options, {:sslv3, {:versions, [:"tlsv1.2", :"tlsv1.1", :tlsv1, :sslv3]}}}}}

image

I just confirmed that it's also an issue in this project/repo (elixir-auth-google-demo),
so I'm fixing it here first as this is a much simpler demo app.

As noted in the auth issue, I think updating the version of plug_cowboy should do the trick:

{:plug_cowboy, "~> 2.0"},

Update to dependency on elixir_auth_github to v1.5 and Update Phoenix to 1.6

With the release of elixir_auth_github at 1.5.0 and Phoenix 1.6 we need to update this demo to confirm everything still works as expected.

Todo

  • Update Elixir to 1.12.3
  • Update to Phoenix 1.6
    • Deletes package.json and unnecessary node.js dependencies! 🎉
  • Update underlying dependency elixir_auth_github to 1.5.0 📦

Here's one we made earlier: dwyl/elixir-auth-github-demo#18

The demo app is currently working on heroku using "old" version: https://elixir-auth-google-demo.herokuapp.com/
image

Remove Webpack

We are getting a build error because WebPack uses arrow functions:
image

We don't need webpack in this project so I'm removing it.

Erlang '24.0' isn't supported yet ... Deploy Latest Version of App to Heroku

@SimonLab thanks for merging the update PR #7
Annoyingly, the deploy doesn't work because the buildpack is incorrect (my fault):
https://dashboard.heroku.com/apps/elixir-auth-google-demo/activity/builds/3cb8e486-9ee9-4cbe-9014-b925f6b3eff5
image

-----> Checking Erlang and Elixir versions
       Will use the following versions:
       * Stack heroku-18
       * Erlang 24.0
       * Elixir v1.12.3 
       Sorry, Erlang '24.0' isn't supported yet or isn't formatted correctly. For a list of supported versions, please see https://github.com/HashNuke/heroku-buildpack-elixir#version-support
 !     Push rejected, failed to compile Elixir app.
 !     Push failed

Just checked https://github.com/HashNuke/heroku-buildpack-elixir-otp-builds/blob/master/otp-versions
and it appears the latest available version is 23.3.2:
image

There is a PR to add OTP 24: HashNuke/heroku-buildpack-elixir-otp-builds#166 but it's sitting waiting ... ⏳

I can take a look at this in the evening. Need to do some "work work" now. ⏳

Todo

  • Downgrade OTP version to 23.3.2
  • Create PR
  • Confirm successful deployment to Heroku

This should only take 2 mins but the lowest label we have is T25m ... see: dwyl/labels#99

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.