# pico-client-auth v0.3.0

**Groups Support** — Group-based access control for pico-fastapi applications.

## What's New

This release adds group-based authorization alongside the existing role-based system. Groups are carried in the JWT `groups` claim and can be enforced at the endpoint level with `@requires_group` or checked programmatically via `SecurityContext`.

## Features

- **`TokenClaims.groups`** — New field (`tuple[str, ...]`, default `()`) carrying group IDs from the JWT
- **`@requires_group("group-id")`** — Endpoint decorator that returns 403 if the user doesn't belong to any of the specified groups
- **`SecurityContext.get_groups()`** — Returns the group IDs for the current request
- **`SecurityContext.has_group(group_id)`** — Boolean check for group membership
- **`SecurityContext.require_group(*group_ids)`** — Raises `InsufficientPermissionsError` if the user isn't in any of the given groups
- **Middleware enforcement** — `AuthFastapiConfigurer` checks `@requires_group` alongside `@requires_role`
- **Docker E2E tests** — `Dockerfile.test` and `Makefile` for containerised test execution

## Usage

```python
from pico_client_auth import requires_group, SecurityContext

@requires_group("engineering", "platform")
async def team_dashboard(self):
    groups = SecurityContext.get_groups()
    return {"groups": groups}

# Programmatic check
if SecurityContext.has_group("engineering"):
    # ...
```

## Dependencies

- pico-ioc >= 2.2.4
- pico-fastapi >= 0.3.0
- python-jose[cryptography] >= 3.5
- httpx >= 0.28

## Compatibility

- Python 3.11, 3.12, 3.13, 3.14
- Fully backward-compatible — `TokenClaims.groups` defaults to `()` for tokens without the claim
