Skip to content
Agentmart
Submit a tool

phoenix-authorization-patterns

Handles all authorization and access control work in Phoenix and LiveView applications.

Skill by igmarin

IndexedMIT★ 5
Write a review

Install

Works with Claude Code, Claude apps, Codex, Cursor, Gemini CLI, GitHub Copilot, VS Code, OpenCode, Goose, Windsurf. Read the repository before you give any tool access to your data.

npx agentmarket install skill/igmarin-phoenix-authorization-patterns

Asks which of your tools to add it to (Claude Code, Codex, Cursor, VS Code, Windsurf, Gemini CLI, Claude Desktop) and shows the change first. See https://agentmart.dev/cli.

Get the weekly diff

The weekly diff: one email a week with new agent tools, notable updates and grade changes, plus security alerts for tools you follow. Double opt-in, one-click unsubscribe.

We use your email only for this newsletter. Privacy

About

Handles all authorization and access control work in Phoenix and LiveView applications. Covers server-side authorization, owner-only patterns, scoped queries, policy modules, controller authorization, and authorization testing. Use when writing permission checks, policy modules, or role-based access controls, or when addressing authorization, access control, permission, policy, role, owner, scoped query, or IDOR concerns.

Use cases: backend, testing, writing

No reviews yet. Installed it? Reviews come from verified installers only. How reviews work

Permissions

What this skill can do and what it asks for, from its SKILL.md. Checked Oct 25, 2026.

Tools
No tools found
Secrets
None asked for
Install scripts
None found

Network hosts it talks to 1

  • codeload.github.com · found in install command

Files it touches

  • ~/.claude/skills/phoenix-authorization-patterns

What's inside

Skill name
phoenix-authorization-patterns
Description
Handles all authorization and access control work in Phoenix and LiveView applications. Covers server-side authorization, owner-only patterns, scoped queries, policy modules, controller authorization, and authorization testing. Use when writing permission checks, policy modules, or role-based access controls, or when addressing authorization, access control, permission, policy, role, owner, scoped query, or IDOR concerns.
License
MIT
Metadata
version: 1.0.0 · user-invocable: true
Instructions
168 lines in SKILL.md · view on GitHub

Files (1)

  • SKILL.md

SKILL.md (first lines)

# Phoenix Authorization Patterns



## RULES — Follow these with no exceptions

**1.** **Always authorize on the server in event handlers** — never rely on UI-only checks
**2.** **Verify resource ownership by comparing `current_scope.user.id` against the resource's `user_id`** — never trust client-sent user IDs
**3.** **Use policy modules for complex authorization** — don't inline permission checks in LiveViews or controllers
**4.** **Add `data-confirm` attribute for destructive UI actions** — client-side confirmation before server round-trip
**5.** **Test both authorized and unauthorized paths** — every `handle_event` that mutates data needs an authz test
**6.** **Scope queries to the current user in contexts** — `where(user_id: ^user_id)` prevents IDOR vulnerabilities


## Authorization Workflow for a New Resource

Follow these steps in order when adding authorization to any new resource:

1. **Add scoped queries in the context** — ensure all queries filter by `user_id` so unauthorized data is never returned
2. **Define policy module rules** — add clauses for every action (`view`, `edit`, `delete`, etc.) before wiring up any LiveView
3. **Add server-side checks in LiveView event handlers** — call `Policy.authorize/3` or compare `current_scope.user.id` against the resource's `user_id` in every `handle_event` that mutates data
4. **Write unauthorized-path tests first** — confirm that a non-owner receives an error and that the mutation does not occur
5. **Only then add UI controls** — hide or disable buttons for unauthorized users *after* server-side checks are verified

**Validation checkpoints:**
- Every context function that returns or mutates a resource is scoped to the current user ✓
- Policy module has a catch-all clause returning `{:error, :unauthorized}` ✓
- Every mutating `handle_event` has a corresponding unauthorized-path test ✓


## Server-Side Authorization in LiveViews

```elixir
defmodule MyAppWeb.PostLive.Show do
  use MyAppWeb, :live_view

  @impl true
  def handle_event("delete", _params, socket) do
    post = socket.assigns.post

    if socket.assigns.current_scope.user.id == post.user_id do
      {:ok, _} = Blog.delete_post(post)
      {:noreply, push_navigate(socket, to: ~p"/posts")}
    else
      {:noreply, put_flash(socket, :error, "Not authorized")}
    end
  end
end
```


## Scoped Queries in Contexts

```elixir
defmodule MyApp.Blog do
  import Ecto.Query

  # Scoped — only returns posts owned by this user
  def list_user_posts(%Scope{user: user}) do
    Post
    |> where(user_id: ^user.id)
    |> order_by(desc: :inserted_at)
    |> Repo.all()
  end

  # Scoped get — returns nil if not owned by user
  def get_user_post(%Scope{user: user}, id) do
    Post
    |> where(user_id: ^user.id)
    |> Repo.get(id)
  end

  # Scoped update — only updates if owned
  def update_user_post(%Scope{user: user}, %Post{} = post, attrs) do
    if post.user_id == user.id do
      post |> Post.changeset(attrs) |> Repo.update()
    else
      {:error, :unauthorized}
    end
  end
end
```


## Policy Modules

For complex permissions (roles, teams, org-level access):

```elixir
defmodule MyApp.Policy do
  alias MyApp.Accounts.User
  alias MyApp.Blog.Post

  def authorize(%User{role: :admin}, _action, _resource), do: :ok

  def authorize(%User{id: user_id}, :edit, %Post{user_id: user_id}), do: :ok
  def authorize(%User{id: user_id}, :delete, %Post{user_id: user_id}), do: :ok
  def authorize(%User{}, :view, %Post{published: true}), do: :ok

  def authorize(_user, _action, _resource), do: {:error, :unauthorized}
end

# Usage in LiveView
case Policy.authorize(user, :delete, post) do
  :ok -> {:ok, _} = Blog.delete_post(post)
  {:error, :unauthorized} -> put_flash(socket, :error, "Not authorized")
end
```


## Testing Authorization

```elixir
describe "authorization" do
  test "owner can delete their post", %{conn: conn} do
    user = user_fixture()
    post = post_fixture(user_id: user.id)
    conn = log_in_user(conn, user)

From igmarin/elixir-phoenix-skills, MIT.

More from igmarin/elixir-phoenix-skills

Signals

Stars
5
Forks
0
Open issues
0
Last commit (this folder)
Sep 28, 2026 (1 month ago)

From GitHub (fetched Oct 24, 2026).

Details

Version
1.0.0
License
MIT
First seen
Oct 24, 2026
Last checked
Oct 24, 2026

More from igmarin

Cite this page

phoenix-authorization-patterns skill. Agent Mart. https://agentmart.dev/skills/igmarin-phoenix-authorization-patterns (last updated 2026-10-24)