OAuth Integration Guide
View SourceThis guide covers implementing OAuth 2.1 authorization flows in your Elixir application using Supabase Auth.
Overview
The OAuth module provides two main capabilities:
- Grant Management: View and revoke third-party app access
- Authorization Flow: Handle OAuth consent requests
Grant Management
Allow users to manage which applications have access to their account.
Listing Grants
def index(conn, _params) do
session = conn.assigns.session
case Supabase.Auth.OAuth.list_grants(client(), session) do
{:ok, grants} -> render(conn, "grants.html", grants: grants)
{:error, _} -> redirect(conn, to: "/")
end
endRevoking Access
def revoke(conn, %{"client_id" => client_id}) do
session = conn.assigns.session
case Supabase.Auth.OAuth.revoke_grant(client(), session, client_id) do
:ok -> redirect(conn, to: "/oauth/grants")
{:error, _} -> redirect(conn, to: "/oauth/grants")
end
endAuthorization Flow
Handle OAuth consent when users authorize third-party applications.
Flow Steps
- User arrives with an
authorization_idparameter - Fetch authorization details
- Show consent screen (or skip if already consented)
- Process approval/denial
- Redirect to the provided URL
Implementation
def authorize(conn, %{"authorization_id" => auth_id}) do
session = conn.assigns.session
case Supabase.Auth.OAuth.get_authorization_details(client(), session, auth_id) do
{:ok, %{redirect_url: url}} when not is_nil(url) ->
# User already consented, skip consent screen
redirect(conn, external: url)
{:ok, details} ->
# Show consent screen with app details
render(conn, "consent.html", details: details, auth_id: auth_id)
{:error, _} ->
redirect(conn, to: "/")
end
end
def approve(conn, %{"authorization_id" => auth_id}) do
session = conn.assigns.session
case Supabase.Auth.OAuth.approve_authorization(client(), session, auth_id) do
{:ok, response} -> redirect(conn, external: response.redirect_url)
{:error, _} -> redirect(conn, to: "/")
end
end
def deny(conn, %{"authorization_id" => auth_id}) do
session = conn.assigns.session
case Supabase.Auth.OAuth.deny_authorization(client(), session, auth_id) do
{:ok, response} -> redirect(conn, external: response.redirect_url)
{:error, _} -> redirect(conn, to: "/")
end
endLiveView Implementation
For LiveView, handle events instead of controller actions:
def mount(%{"authorization_id" => auth_id}, _session, socket) do
session = socket.assigns.session
case Supabase.Auth.OAuth.get_authorization_details(client(), session, auth_id) do
{:ok, %{redirect_url: url}} when not is_nil(url) ->
{:ok, push_navigate(socket, external: url)}
{:ok, details} ->
{:ok, assign(socket, details: details, auth_id: auth_id)}
{:error, _} ->
{:ok, push_navigate(socket, to: "/")}
end
end
def handle_event("approve", _, socket) do
case Supabase.Auth.OAuth.approve_authorization(
client(),
socket.assigns.session,
socket.assigns.auth_id
) do
{:ok, response} -> {:noreply, push_navigate(socket, external: response.redirect_url)}
{:error, _} -> {:noreply, socket}
end
end
def handle_event("deny", _, socket) do
case Supabase.Auth.OAuth.deny_authorization(
client(),
socket.assigns.session,
socket.assigns.auth_id
) do
{:ok, response} -> {:noreply, push_navigate(socket, external: response.redirect_url)}
{:error, _} -> {:noreply, socket}
end
endKey Concepts
Authorization Details
The authorization details contain information about the OAuth request:
- Application name and metadata
- Requested scopes
- Whether user previously consented
Early Exit
When get_authorization_details/3 returns a redirect_url, the user has already consented to the requested scopes. Skip showing the consent screen and redirect immediately.
Session Requirement
All OAuth operations require a valid authenticated session. Ensure users are logged in before accessing OAuth endpoints.
Error Handling
Handle errors gracefully by redirecting to safe locations. Avoid exposing error details to prevent information leakage about your OAuth configuration.