# `PhoenixGenApi.Permission`
[🔗](https://github.com/ohhi-vn/phoenix_gen_api/blob/main/lib/phoenix_gen_api/permission.ex#L1)

Provides permission checking functionality for API requests.

This module implements a flexible permission system that can verify whether a user
has the right to execute a specific request. Permissions can be disabled, or configured
to check that certain request arguments match the requesting user's identity.

## Permission Modes

### Disabled Permissions (`false`)
When `check_permission: false` is set in the FunConfig, all permission checks pass.
This is useful for public endpoints that don't require authentication or authorization.

### Any Authenticated (`:any_authenticated`)
When `check_permission: :any_authenticated` is configured, the system verifies that
the request has a valid `user_id`. Any authenticated user is allowed access.

### Argument-Based Permissions (`{:arg, arg_name}`)
When `check_permission: {:arg, arg_name}` is configured, the system verifies that
the value of the specified argument matches the request's `user_id`. This ensures
users can only access their own data.

For example, with `{:arg, "user_id"}`, a request from user "123" will only be
allowed if `request.args["user_id"] == "123"`.

### Role-Based Permissions (`{:role, allowed_roles}`)
When `check_permission: {:role, allowed_roles}` is configured, the system verifies
that the user has one of the allowed roles. Roles are checked against the
`request.user_roles` field (must be a list of strings or atoms).

For example, with `{:role, ["admin", "moderator"]}`, only users with those roles
are allowed access.

## Examples

    # Public endpoint - no permission check
    config = %FunConfig{
      request_type: "get_public_data",
      check_permission: false
    }

    request = %Request{user_id: "any_user"}
    Permission.check_permission(request, config)
    # => true

    # Any authenticated user
    config = %FunConfig{
      request_type: "get_profile",
      check_permission: :any_authenticated
    }

    request = %Request{user_id: "user_123"}
    Permission.check_permission(request, config)
    # => true

    request = %Request{user_id: nil}
    Permission.check_permission(request, config)
    # => false

    # User-specific endpoint - must match user_id
    config = %FunConfig{
      request_type: "get_user_profile",
      check_permission: {:arg, "user_id"}
    }

    # This passes - user accessing their own data
    request = %Request{
      user_id: "user_123",
      args: %{"user_id" => "user_123"}
    }
    Permission.check_permission(request, config)
    # => true

    # This fails - user trying to access another user's data
    request = %Request{
      user_id: "user_123",
      args: %{"user_id" => "user_999"}
    }
    Permission.check_permission(request, config)
    # => false

    # Role-based access
    config = %FunConfig{
      request_type: "delete_user",
      check_permission: {:role, ["admin"]}
    }

    request = %Request{
      user_id: "user_123",
      user_roles: ["admin"]
    }
    Permission.check_permission(request, config)
    # => true

## Security Considerations

- Always use `check_permission!/2` in the execution path to raise on failures
- The `check_permission/2` function is non-raising and returns a boolean
- Missing arguments result in permission denial (returns `false`)
- Permission checks happen before argument validation and function execution
- All permission failures are logged for audit purposes
- Use specific permission modes rather than `false` when possible

# `check_permission`

Exception raised when a permission check fails.

Contains details about the request and the permission mode that was denied.

# `check_permission!`

Checks permission and raises an exception if the check fails.

This is the raising version of `check_permission/2`. It should be used in the
request execution pipeline where permission failures should halt processing.

## Parameters

  - `request` - The `Request` struct containing user information and arguments
  - `fun_config` - The `FunConfig` struct with permission settings

## Returns

  - `nil` - Permission check passed (function returns nothing on success)

## Raises

  - `PermissionDenied` - If the permission check fails

## Examples

    request = %Request{
      user_id: "user_123",
      args: %{"user_id" => "user_999"}
    }

    config = %FunConfig{check_permission: {:arg, "user_id"}}

    # This will raise because user_ids don't match
    Permission.check_permission!(request, config)
    # ** (PhoenixGenApi.Permission.PermissionDenied) Permission denied...

## Notes

- Logs a warning with request details when permission is denied
- Always called before request execution in the Executor module
- Returns nothing on success (only side effect is potential exception)

---

*Consult [api-reference.md](api-reference.md) for complete listing*
