Skip to content

Oauth on PhoenixΒΆ

Elixir has a package Ueberauth that provides Oauth for phoenix. We will use github authentication strategy.

To install it, we add the dependencies to mix.exs:

{:ueberauth, "~> 0.3"},
{:ueberauth_github, "~> 0.4"}
def application do
    [mod: {Discuss, []},
     applications: [:phoenix, :phoenix_pubsub, :phoenix_html, :cowboy, :logger, :gettext,
                    :phoenix_ecto, :postgrex, :ueberauth, :ueberauth_github]]
  end

Next, well need to make a new OAuth application on github in https://github.com/settings/applications/new.

As the Authorization callback URL we provide http://localhost:4000/auth/github/callback.

Then, we get a Client ID and Client Secret keys.

Add the following key to the config/config.exs.

import_config "oauth.secret.exs"

Create config/oauth.secret.exs with following content:

use Mix.Config

config :ueberauth, Ueberauth,
  providers: [
    github: { Ueberauth.Strategy.Github, [default_scope: "user"]}
  ]

config :ueberauth, Ueberauth.Strategy.Github.OAuth,
  client_id: "the_id",
  client_secret: "the_secret"

Now we add new routes:


  scope "/auth", Discuss do
    pipe_through :browser

    get "/signout", AuthController, :signout
    get "/:provider", AuthController, :request
    get "/:provider/callback", AuthController, :callback
  end

Add User model by using mix phoenix.gen.model User users email:string provider:string token:string

It will generate the model as well as the migration.

And now, add the web/controllers/auth_controller.ex

defmodule Discuss.AuthController do

  use Discuss.Web, :controller
  alias Discuss.User

  plug Ueberauth

  def callback(%{assigns: %{ueberauth_auth: auth}} = conn, _params) do
    # IO.inspect(conn)
    user_params = %{token: auth.credentials.token, email: auth.info.email, provider: "github"}
    changeset = User.changeset(%User{}, user_params)
    signin(conn, changeset)
  end

  defp signin(conn, changeset) do
    case insert_or_update_user(changeset) do
      {:ok, user} ->
        conn
        |> put_flash(:info, "Welcome back!")
        |> put_session(:user_id, user.id)
        |> redirect(to: topic_path(conn, :index))
      {:error, _reason} ->
        conn
        |> put_flash(:error, "Error signing in")
        |> redirect(to: topic_path(conn, :index))
    end
  end

  defp insert_or_update_user(changeset) do
    case Repo.get_by(User, email: changeset.changes.email) do
      nil ->
        Repo.insert(changeset)
      user ->
        {:ok, user}
    end
  end

  def signout(conn, _params) do
    conn
    |> configure_session(drop: true)
    |> redirect(to: topic_path(conn, :index))
  end

end