michael_teter
How to externalize user authentication within Phoenix?
Can someone with current experience suggest a path on how to get started externalizing user authentication within Phoenix? I would like to give my users the ability to register/sign-in using Google, Facebook, etc.
Further, if I integrate with enough external providers, I assume that means I could (potentially?) forego entirely the responsibility of storing/managing users passwords. Is that a reasonable assumption?
There is a lot of information about this topic, but most of it seems dated… and the Elixir/Phoenix world moves quickly. I’d like to avoid starting on a dead-end path :).
Thanks in advance!
Most Liked
danschultzer
Do you still want to register the users? I wrote CoherenceAssent to handle multi-provider login. While it’s built to use Coherence, I’ve been using it for just Github OAuth login in an admin interface where I just store the user information in the session. The controller looks like this:
defmodule MyAdminApp.AuthController do
use MyAdminApp, :controller
@organization "my-organization"
@spec new(Conn.t, map) :: Conn.t
def new(conn, _params) do
config = Keyword.put(config(), :redirect_uri, callback_url(conn))
{:ok, %{conn: conn, url: url}} = CoherenceAssent.Strategy.Github.authorize_url(conn, config)
redirect(conn, external: url)
end
@spec callback(Conn.t, map) :: Conn.t
def callback(conn, params) do
params = Map.merge(%{"redirect_uri" => callback_url(conn)}, params)
conn
|> CoherenceAssent.Strategy.Github.callback(config(), params)
|> verify_organization()
|> login_or_redirect()
end
defp login_or_redirect({:ok, %{conn: conn, user: user}}) do
conn
|> put_session(:current_admin_user, user)
|> redirect(to: index_path(conn, :index))
end
defp login_or_redirect({:error, %{error: error}}) do
raise error
end
defp config do
config = Application.get_env(:my_admin_app, :admin_github_provider) || raise "Need to set :admin_github_provider first!"
Keyword.put(config, :authorization_params, [scope: "read:user,user:email,read:org"])
end
defp verify_organization({:error, error}), do: {:error, error}
defp verify_organization({:ok, %{conn: conn, client: client, user: user}}) do
case OAuth2.Client.get(client, "/user/orgs") do
{:ok, %OAuth2.Response{body: orgs}} ->
case Enum.find_value(orgs, &(&1["login"] == @organization)) do
true -> {:ok, %{conn: conn, user: user}}
_ -> {:error, %{error: "#{user["nickname"]} is not a member of #{@organization}"}}
end
{:error, error} ->
{:error, %{conn: conn, error: error}}
end
end
defp callback_url(conn) do
auth_url(conn, :callback)
end
end
And the plug looks like this:
defmodule MyAdminApp.Plug.RequireLogin do
@moduledoc false
import Plug.Conn
import Phoenix.Controller, only: [redirect: 2]
alias MyAdminApp.Router.Helpers
@behaviour Plug
@dialyzer [
{:nowarn_function, call: 2},
{:nowarn_function, init: 1},
]
@spec init(Keyword.t) :: [tuple]
def init(options) do
%{option: options}
end
@spec call(Plug.Conn.t, any) :: Plug.Conn.t
def call(conn, _opts) do
user = get_session(conn, :current_admin_user)
if user do
conn
|> assign(:current_admin_user, user)
else
conn
|> redirect(to: Helpers.auth_path(conn, :new))
|> halt
end
end
end
Routes:
# ...
pipeline :protected do
plug NomadRentalAdmin.Plug.RequireLogin
end
scope "/", MyAdminApp do
pipe_through [:browser]
get "/auth", AuthController, :new
get "/auth/callback", AuthController, :callback
end
# ...
It’s a very basic setup (since we’re just using it to log in to an internal admin interface with our Github organization), but might be something like this you’re looking for?
If you want to register the users still then I recommend checking out the readme for CoherenceAssent. It takes a minute, and then you can remove the ability to change the password on user admin page.
Kurisu
Great work!
That is what I’m looking for. I’m using Phauxth instead of Coherence but after what I saw on your own library Pow, I will definitely give it a try.
Thank you for sharing this. ^^
Last Post!
danschultzer
Thanks! I hope it works for you.
PowAssent has been improved to not be dependent on Plug, so if you use it without any user registration like in the example above, the API is a little different. But if you use Pow for user registration then there’s nothing you have to think about ![]()
Popular in Questions
Other popular topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #phoenix_html
- #iex
- #blog-post
- #graphql
- #genstage
- #ai
- #websockets
- #supervisor
- #elixirconf-us
- #advent-of-code
- #distillery
- #processes
- #api
- #forms
- #metaprogramming
- #security
- #hex









