Opinionated authentication library for Phoenix LiveView applications using WorkOS AuthKit.
Add sgiath_auth to your list of dependencies in mix.exs:
def deps do
[
{:sgiath_auth, github: "sgiath/auth"}
]
end# config/runtime.exs
config :sgiath_auth,
workos_client_id: System.fetch_env!("WORKOS_CLIENT_ID"),
workos_secret_key: System.fetch_env!("WORKOS_SECRET_KEY"),
callback_url: "https://yourapp.com/auth/callback"config :sgiath_auth,
# organization to add all new users to, useful when running multiple apps under
# one WorkOS account and separating users by organizations
organization_id: "org_...",
# Path to redirect unauthenticated users (default: "/sign-in")
sign_in_path: "/login",
# Path to redirect after sign-in/sign-out (default: "/")
default_path: "/dashboard",
# Module implementing SgiathAuth.Profile behaviour (default: nil)
profile_module: MyApp.Profile# lib/my_app/application.ex
def start(_type, _args) do
children = [
# ... other children
SgiathAuth.Supervisor
]
opts = [strategy: :one_for_one, name: MyApp.Supervisor]
Supervisor.start_link(children, opts)
end# lib/my_app_web/router.ex
scope "/auth", SgiathAuth do
pipe_through [:browser]
get "/sign-in", Controller, :sign_in
get "/sign-up", Controller, :sign_up
get "/sign-out", Controller, :sign_out
get "/callback", Controller, :callback
end# lib/my_app_web/router.ex
import SgiathAuth
pipeline :browser do
# ... existing plugs
plug :fetch_session
plug :fetch_current_scope
end# lib/my_app_web.ex
def live_view do
quote do
use Phoenix.LiveView, layout: {MyAppWeb.Layouts, :app}
on_mount {SgiathAuth, :mount_current_scope}
# or for routes requiring authentication:
# on_mount {SgiathAuth, :require_authenticated}
end
endFor regular controllers:
# lib/my_app_web/router.ex
import SgiathAuth
pipeline :require_authenticated do
plug :require_authenticated_user
end
scope "/", MyAppWeb do
pipe_through [:browser, :require_authenticated]
# Protected routes
endFor LiveView, use the :require_authenticated hook:
live_session :authenticated, on_mount: [{SgiathAuth, :require_authenticated}] do
live "/dashboard", DashboardLive
endTo populate the profile field in SgiathAuth.Scope with application-specific data, implement the SgiathAuth.Profile behaviour:
defmodule MyApp.Profile do
@behaviour SgiathAuth.Profile
@impl SgiathAuth.Profile
def load_profile(%{"id" => user_id}) do
MyApp.UserProfile
|> where(user_id: ^user_id)
|> MyApp.Repo.all()
|> case do
[] ->
# does not have a profile, create one automatically or return nil to deal with it later
nil
[%MyApp.UserProfile{} = profile] ->
# user have one profile
profile
profiles when is_list(profiles) ->
# user have multiple profiles, either invariant or intended
nil
end
end
endThen configure it:
config :sgiath_auth, profile_module: MyApp.ProfileThe profile will be available in conn.assigns.current_scope.profile and socket.assigns.current_scope.profile.
The SgiathAuth.Scope struct contains:
user- The WorkOS user mapprofile- Application-specific profile data (ifprofile_moduleis configured)admin- The admin email when using impersonation (from JWTact.subclaim)