> ## Documentation Index
> Fetch the complete documentation index at: https://docs.go-mizu.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# RBAC

> Role-based access control middleware for authorization.

## Overview

The `rbac` middleware provides role-based access control, allowing you to restrict routes based on user roles and permissions.

Use it when you need:

* Role-based route protection
* Permission-based access control
* Multi-level authorization

## Installation

```go theme={null}
import "github.com/go-mizu/mizu/middlewares/rbac"
```

## Quick Start

```go theme={null}
app := mizu.New()

// Get user role from context
getRoles := func(c *mizu.Ctx) []string {
    user := c.Get("user").(User)
    return user.Roles
}

// Require admin role
adminOnly := rbac.RequireRole(getRoles, "admin")

app.Get("/admin", adminHandler, adminOnly)
```

## Configuration

### Options

| Option           | Type                       | Description                 |
| ---------------- | -------------------------- | --------------------------- |
| `GetRoles`       | `func(*mizu.Ctx) []string` | Function to get user roles  |
| `GetPermissions` | `func(*mizu.Ctx) []string` | Function to get permissions |
| `ErrorHandler`   | `func(*mizu.Ctx) error`    | Custom 403 handler          |

## Examples

### Simple Role Check

```go theme={null}
getRoles := func(c *mizu.Ctx) []string {
    claims := jwt.GetClaims(c)
    return claims["roles"].([]string)
}

// Single role
app.Get("/admin", handler, rbac.RequireRole(getRoles, "admin"))

// Any of multiple roles
app.Get("/dashboard", handler, rbac.RequireAnyRole(getRoles, "admin", "manager"))

// All roles required
app.Get("/super", handler, rbac.RequireAllRoles(getRoles, "admin", "superuser"))
```

### Permission-Based

```go theme={null}
getPerms := func(c *mizu.Ctx) []string {
    return getUserPermissions(c)
}

// Single permission
app.Post("/users", createUser, rbac.RequirePermission(getPerms, "users:create"))

// Multiple permissions
app.Delete("/users/:id", deleteUser, rbac.RequireAllPermissions(getPerms, "users:delete", "admin:access"))
```

### Hierarchical Roles

```go theme={null}
hierarchy := rbac.NewHierarchy()
hierarchy.Add("superadmin", "admin", "user")
hierarchy.Add("admin", "moderator", "user")
hierarchy.Add("moderator", "user")

// superadmin and admin can access
app.Get("/manage", handler, rbac.RequireRoleWithHierarchy(getRoles, hierarchy, "admin"))
```

### Custom Error Handler

```go theme={null}
app.Use(rbac.WithOptions(rbac.Options{
    GetRoles: getRoles,
    ErrorHandler: func(c *mizu.Ctx) error {
        return c.JSON(403, map[string]string{
            "error": "You don't have permission to access this resource",
        })
    },
}))
```

### Route Groups

```go theme={null}
// Admin routes
admin := app.Group("/admin")
admin.Use(rbac.RequireRole(getRoles, "admin"))
admin.Get("/users", listUsers)
admin.Post("/users", createUser)

// Manager routes
manager := app.Group("/manager")
manager.Use(rbac.RequireAnyRole(getRoles, "admin", "manager"))
manager.Get("/reports", viewReports)
```

## API Reference

### Functions

```go theme={null}
// RequireRole requires a specific role
func RequireRole(getRoles func(*mizu.Ctx) []string, role string) mizu.Middleware

// RequireAnyRole requires any of the specified roles
func RequireAnyRole(getRoles func(*mizu.Ctx) []string, roles ...string) mizu.Middleware

// RequireAllRoles requires all specified roles
func RequireAllRoles(getRoles func(*mizu.Ctx) []string, roles ...string) mizu.Middleware

// RequirePermission requires a specific permission
func RequirePermission(getPerms func(*mizu.Ctx) []string, perm string) mizu.Middleware

// RequireAllPermissions requires all permissions
func RequireAllPermissions(getPerms func(*mizu.Ctx) []string, perms ...string) mizu.Middleware

// WithOptions creates middleware with configuration
func WithOptions(opts Options) mizu.Middleware
```

### Hierarchy

```go theme={null}
// NewHierarchy creates role hierarchy
func NewHierarchy() *Hierarchy

// Add defines parent-child relationships
func (h *Hierarchy) Add(parent string, children ...string)

// RequireRoleWithHierarchy checks against hierarchy
func RequireRoleWithHierarchy(getRoles func(*mizu.Ctx) []string, h *Hierarchy, role string) mizu.Middleware
```

## Technical Details

### Implementation Overview

The RBAC middleware is built around a User struct that contains roles and permissions:

```go theme={null}
type User struct {
    ID          string
    Roles       []string
    Permissions []string
}
```

### Context Management

User information is stored in the request context using a private context key:

* `Set(c *mizu.Ctx, user *User)` - Stores user in context
* `Get(c *mizu.Ctx) *User` - Retrieves user from context
* Returns nil if no user is found in context

### Role and Permission Checking

The middleware provides several helper functions for checking access:

* `HasRole(c *mizu.Ctx, role string) bool` - Checks if user has a specific role
* `HasAnyRole(c *mizu.Ctx, roles ...string) bool` - Checks if user has any of the specified roles
* `HasAllRoles(c *mizu.Ctx, roles ...string) bool` - Checks if user has all specified roles
* `HasPermission(c *mizu.Ctx, permission string) bool` - Checks if user has a specific permission

### Middleware Functions

Role-based middlewares:

* `RequireRole(role string)` - Requires a specific role
* `RequireAnyRole(roles ...string)` - Requires any of the specified roles (OR logic)
* `RequireAllRoles(roles ...string)` - Requires all specified roles (AND logic)

Permission-based middlewares:

* `RequirePermission(permission string)` - Requires a specific permission
* `RequireAnyPermission(permissions ...string)` - Requires any of the permissions
* `RequireAllPermissions(permissions ...string)` - Requires all permissions

Convenience middlewares:

* `Admin()` - Shorthand for RequireRole("admin")
* `Authenticated()` - Checks if any user is present in context

### Error Handling

* Default behavior returns HTTP 403 Forbidden with "Access denied" text
* Returns HTTP 401 Unauthorized with "Authentication required" for unauthenticated users
* Custom error handlers can be wrapped using `WithErrorHandler`

## Best Practices

* Use JWT claims or session for role storage
* Implement role hierarchy for complex permissions
* Cache permission checks for performance
* Log authorization failures for security monitoring

## Testing

| Test Case                           | Description                                          | Expected Behavior                                                        |
| ----------------------------------- | ---------------------------------------------------- | ------------------------------------------------------------------------ |
| TestRequireRole                     | User with required role accessing protected route    | Returns 200 OK, access granted                                           |
| TestRequireRole\_Forbidden          | User without required role accessing protected route | Returns 403 Forbidden, access denied                                     |
| TestRequireAnyRole                  | User with one of multiple required roles             | Returns 200 OK, access granted when user has editor role                 |
| TestRequireAllRoles (has all)       | User with all required roles                         | Returns 200 OK, access granted when user has both admin and editor roles |
| TestRequireAllRoles (missing one)   | User missing one of required roles                   | Returns 403 Forbidden, access denied when user has admin but not editor  |
| TestRequirePermission               | User with required permission accessing resource     | Returns 200 OK, access granted with write:posts permission               |
| TestAdmin                           | User with admin role accessing admin route           | Returns 200 OK, access granted                                           |
| TestAuthenticated (authenticated)   | Authenticated user accessing protected route         | Returns 200 OK, access granted                                           |
| TestAuthenticated (unauthenticated) | Unauthenticated user accessing protected route       | Returns 401 Unauthorized, authentication required                        |
| TestHasRole                         | Checking if user has specific roles                  | Returns true for user role, false for admin role                         |
| TestGet                             | Retrieving user from context                         | Returns user object with correct ID                                      |
| TestNoUser                          | Checking role without user in context                | Returns false, no access without user                                    |

## Related Middlewares

* [jwt](/middlewares/jwt) - JWT authentication
* [basicauth](/middlewares/basicauth) - Basic authentication
* [keyauth](/middlewares/keyauth) - API key authentication
