Google OAuth 2.0 authentication in Phoenix

Let’s create new Phoenix application:

mix phoenix.new app

Dependencies

We are going to use oauth2 library in our application. First we need to update our dependencies in mix.exs file:

# mix.exs
defmodule App.Mixfile do
  # ...
  def application do
    [mod: {App, []},
     applications: [:phoenix, :phoenix_html, :cowboy, :logger,
                    :phoenix_ecto, :postgrex, :oauth2]]
  end
  # ...
  defp deps do
    [{:phoenix, "~> 1.0.2"},
     {:phoenix_ecto, "~> 1.1"},
     {:postgrex, ">= 0.0.0"},
     {:phoenix_html, "~> 2.1"},
     {:phoenix_live_reload, "~> 1.0", only: :dev},
     {:cowboy, "~> 1.0"},
     {:oauth2, "~> 0.3"}
   ]
  end
end

Then we update dependencies with:

mix deps.get

Routes

Now we are good with dependencies, so it’s time to add routes:

# web/router.ex
defmodule App.Router do
  # ...
  scope "/auth", App do
    pipe_through :browser # Use the default browser stack

    get "/:provider", AuthController, :index
    get "/:provider/callback", AuthController, :callback
  end
  # ...
end

AuthController

Next thing is to implement AuthController

# web/controllers/auth_controller.ex
defmodule App.AuthController do
  use App.Web, :controller

  def index(conn, %{"provider" => provider}) do
    redirect conn, external: authorize_url!(provider)
  end

  def callback(conn, %{"provider" => provider, "code" => code}) do
    token = get_token!(provider, code)
    user = get_user!(provider, token)

    conn
    |> put_session(:current_user, user)
    |> put_session(:access_token, token.access_token)
    |> redirect(to: "/")
  end

  defp authorize_url!("google") do
    Google.authorize_url!(scope: "email profile")
  end

  defp authorize_url!(_) do
    raise "No matching provider available"
  end

  defp get_token!("google", code) do
    Google.get_token!(code: code)
  end

  defp get_token!(_, _) do
    raise "No matching provider available"
  end

  defp get_user!("google", token) do
    user_url = "https://www.googleapis.com/plus/v1/people/me/openIdConnect"
    OAuth2.AccessToken.get!(token, user_url)
  end
end

Authentication strategy

Last thing to implement is Google module

# web/oauth/google.ex
defmodule Google do
  use OAuth2.Strategy

  alias OAuth2.Strategy.AuthCode

  def client do
    OAuth2.Client.new([
      strategy: __MODULE__,
      client_id: System.get_env("CLIENT_ID"),
      client_secret: System.get_env("CLIENT_SECRET"),
      redirect_uri: System.get_env("REDIRECT_URI"),
      site: "https://accounts.google.com",
      authorize_url: "https://accounts.google.com/o/oauth2/auth",
      token_url: "https://accounts.google.com/o/oauth2/token"
    ])
  end

  def authorize_url!(params \\ []) do
    OAuth2.Client.authorize_url!(client(), params)
  end

  def get_token!(params \\ [], headers \\ []) do
    OAuth2.Client.get_token!(client(), params, headers)
  end

  # strategy callbacks

  def authorize_url(client, params) do
    AuthCode.authorize_url(client, params)
  end

  def get_token(client, params, headers) do
    client
    |> put_header("Accept", "application/json")
    |> AuthCode.get_token(params, headers)
  end
end

Basically we finished implementing authentication but we see no difference in our application. At least let’s add button and display information after we are logged.

Let’s start from replacing content from web/templates/page/index.html.eex with:

<!-- web/templates/page/index.html.eex -->
<%= if @current_user do %>
  <h2>Welcome, <%= @current_user["name"] %>!</h2>
<% else %>
  <%= link to: auth_path(@conn, :index, "google"), class: "btn btn-primary" do %>
    Sign in with Google
  <% end %>
<% end %>

Last changes we introduce in PageController

# web/controllers/page_controller.ex
defmodule App.PageController do
  use App.Web, :controller

  def index(conn, _params) do
    conn
    |> assign(:current_user, get_session(conn, :current_user))
    |> render "index.html"
  end
end

Result

Before authentication we should see:

before_authentication

and after:

after_authentication

Resources

In implementing Google OAuth 2.0 authentication I found helpful source code from repositories:

Posted on 28/09/2015, in Inne. Bookmark the permalink. Dodaj komentarz.

Skomentuj

Wprowadź swoje dane lub kliknij jedną z tych ikon, aby się zalogować:

Logo WordPress.com

Komentujesz korzystając z konta WordPress.com. Log Out / Zmień )

Zdjęcie z Twittera

Komentujesz korzystając z konta Twitter. Log Out / Zmień )

Facebook photo

Komentujesz korzystając z konta Facebook. Log Out / Zmień )

Google+ photo

Komentujesz korzystając z konta Google+. Log Out / Zmień )

Connecting to %s

%d bloggers like this: