Hey Everyone,
I’ve been fighting this one for more than a day and decided to reach out. I’m sure it’s something trivial but I cannot seem to fix it
I’m building a simple admin to manage Organizations and Accounts. The Ueberauth with Google side seems to work fine, I can see a user being created in my database. However, upon the request coming back and hitting the callback, things go awry (as this is where Guardian comes to play, obviously). If y’all wouldn’t mind affording me a few seconds to look at my code?
router.ex
pipeline :browser_auth do
plug Admin.Auth.Pipeline
end
pipeline :browser_ensure_auth do
plug Guardian.Plug.EnsureAuthenticated
end
scope "/auth", AdminWeb do
pipe_through [:browser, :browser_auth]
get "/login", SessionController, :login
get "/logout", SessionController, :delete
get "/:provider", SessionController, :request
get "/:provider/callback", SessionController, :create
end
scope "/", AdminWeb do
pipe_through [:browser, :browser_auth, :browser_ensure_auth]
get "/", DashboardController, :index
resources "/organizations", OrganizationController, only: [:index, :new, :create, :delete]
resources "/accounts", AccountController
end
session_controller.ex
defmodule AdminWeb.SessionController do
use AdminWeb, :controller
plug Ueberauth
alias Admin.Repo
alias Admin.Accounts.Account
def login(conn, _params) do
render conn, "login.html"
end
def create(%{assigns: %{ueberauth_auth: auth}} = conn, _params) do
#map off info struct
%Ueberauth.Auth.Info{
email: account_email,
first_name: account_first_name,
image: account_photo,
last_name: account_last_name} = auth.info
# populate the params, always create as a viewer
account_params = %{
token: auth.credentials.token,
first_name: account_first_name,
last_name: account_last_name,
photo: account_photo,
email: account_email,
provider: "google",
roles: ["viewer"]
}
changeset = Account.changeset(%Account{}, account_params)
case insert_or_update_account(changeset) do
{:ok, account} ->
Guardian.Plug.current_resource(conn)
conn
|> Guardian.Plug.sign_in(account)
|> put_flash(:info, "Thank you for signing in!")
|> redirect(to: Routes.dashboard_path(conn, :index))
{:error, _reason} ->
conn
|> put_flash(:error, "Error signing in")
|> redirect(to: Routes.session_path(conn, :login))
end
end
defp insert_or_update_account(changeset) do
case Repo.get_by(Account, email: changeset.changes.email) do
nil ->
Repo.insert(changeset)
account ->
{:ok, account}
end
end
def delete(conn, _params) do
conn
|> Guardian.Plug.sign_out()
|> redirect(to: Routes.session_path(conn, :login))
end
end
guardian.ex
defmodule Admin.Auth.Guardian do
use Guardian, otp_app: :admin
alias Admin.Repo
alias Admin.Accounts.Account
def subject_for_token(%Account{} = account, _claims) do
{:ok, "Account:#{account.id}"}
end
def resource_from_claims(claims) do
IO.inspect claims
case claims["sub"] do
"Account:" <> account_id ->
case Repo.get!(Account, account_id) do
nil ->
{:error, :account_not_found}
account ->
{:ok, account}
end
_ ->
{:error, :account_not_found}
end
end
end
serializer.ex
defmodule Admin.Auth.GuardianSerializer do
@behaviour Guardian.Serializer
alias Admin.Repo
alias Admin.Accounts.Account
def for_token(account = %Account{}), do: {:ok, "Account:#{account.id}"}
def for_token(_), do: {:error, "Unknown resource type"}
def from_token("Account:" <> id), do: {:ok, Repo.get(Account, id)}
def from_token(_), do: {:error, "Unknown resource type"}
end
pipeline.ex
defmodule Admin.Auth.Pipeline do
use Guardian.Plug.Pipeline,
otp_app: :admin,
module: Admin.Auth.Guardian,
error_handler: Admin.Auth.ErrorHandler
@claims %{iss: "Admin"}
plug Guardian.Plug.VerifySession, claims: @claims
plug Guardian.Plug.VerifyHeader, claims: @claims, realm: "Bearer"
plug Guardian.Plug.LoadResource, allow_blank: true
end
error_handler.ex
defmodule Admin.Auth.ErrorHandler do
import Plug.Conn
require Logger
@behaviour Guardian.Plug.ErrorHandler
@impl Guardian.Plug.ErrorHandler
def auth_error(conn, {type, reason}, _opts) do
Logger.warn(Jason.encode!(%{message: to_string(type)}), [])
Phoenix.Controller.redirect(conn, to: AdminWeb.Router.Helpers.session_path(conn, :login))
end
end
config.exs
config :guardian, Admin.Auth.Guardian,
issuer: "Admin",
verify_issuer: true,
secret_key: "key",
serializer: Admin.Auth.GuardianSerializer
I feel like I followed the Getting Started guide pretty closely, but no dice