# FastAPI Principal

***

**1. Create a simple FastAPI application with Principal authentication**

```python
from fastapi import FastAPI, Request
from fastapi_principal import Principal, Permission, PermissionRequired

app = FastAPI()

# Define the permission
permission = Permission("my_permission")

# Define the Principal factory
async def principal_factory(request: Request) -> Principal:
    return Principal(
        id="user-id",
        roles={"admin", "user"},
        permissions={permission},
        extra={"email": "user@example.com"},
    )

# Add the Principal factory to the app
app.dependency_overrides[Principal] = principal_factory

# Define a route that requires the permission
@app.post("/protected-route")
@PermissionRequired(permission)
async def protected_route(principal: Principal):
    return {"message": "Hello, {}".format(principal.id)}
```

**2. Use Principal to authorize a user using an API token**

```python
from fastapi import FastAPI, Request, HTTPException
from fastapi_principal import Principal, Permission, PermissionRequired
from jose import JWTError, jwt

app = FastAPI()

# Define the permission
permission = Permission("my_permission")

# Define the Principal factory
async def principal_factory(request: Request) -> Principal:
    authorization_header = request.headers.get("Authorization")
    if not authorization_header or not authorization_header.startswith("Bearer "):
        raise HTTPException(status_code=401, detail="Missing or invalid authorization header")

    token = authorization_header.split(" ")[1]
    try:
        payload = jwt.decode(token, "my_secret", algorithms=["HS256"])
    except JWTError:
        raise HTTPException(status_code=401, detail="Invalid token")

    return Principal(
        id=payload["user_id"],
        roles=payload["roles"],
        permissions={permission},
        extra={"email": payload["email"]},
    )

# Add the Principal factory to the app
app.dependency_overrides[Principal] = principal_factory

# Define a route that requires the permission
@app.post("/protected-route")
@PermissionRequired(permission)
async def protected_route(principal: Principal):
    return {"message": "Hello, {}".format(principal.id)}
```

**3. Use Principal to authorize a user using a database**

```python
from fastapi import FastAPI, Request, HTTPException
from fastapi_principal import Principal, Permission, PermissionRequired
from tortoise.models import Model
from tortoise import fields

app = FastAPI()

# Define the User model
class User(Model):
    id = fields.IntField(pk=True)
    username = fields.CharField(max_length=255, unique=True)
    password = fields.CharField(max_length=255)
    roles = fields.JSONField(default=list)
    permissions = fields.JSONField(default=list)

# Define the permission
permission = Permission("my_permission")

# Define the Principal factory
async def principal_factory(request: Request) -> Principal:
    username = request.form.get("username")
    password = request.form.get("password")

    user = await User.get_or_none(username=username)
    if not user or not user.check_password(password):
        raise HTTPException(status_code=401, detail="Invalid credentials")

    return Principal(
        id=user.id,
        roles=user.roles,
        permissions={permission},
        extra={"email": user.email},
    )

# Add the Principal factory to the app
app.dependency_overrides[Principal] = principal_factory

# Define a route that requires the permission
@app.post("/protected-route")
@PermissionRequired(permission)
async def protected_route(principal: Principal):
    return {"message": "Hello, {}".format(principal.id)}
```

**4. Use Principal to authorize a user using OAuth2**

```python
from fastapi import FastAPI, Request, HTTPException
from fastapi_principal import Principal, Permission, PermissionRequired
from fastapi.middleware.oauth2 import OAuth2Middleware
from fastapi.security.oauth2 import OAuth2PasswordBearer

# Create the OAuth2 middleware
oauth2_middleware = OAuth2Middleware(
    token_url="https://example.com/oauth/token",
    authorize_url="https://example.com/oauth/authorize",
    client_id="my_client_id",
    client_secret="my_client_secret",
)

# Create the OAuth2 password bearer
oauth2_scheme = OAuth2PasswordBearer(
    tokenUrl="https://example.com/oauth/token",
    scopes={"my_permission": "My permission"},
)

# Create the FastAPI application
app = FastAPI()

# Define the permission
permission = Permission("my_permission")

# Define the Principal factory
async def principal_factory(request: Request) -> Principal:
    token = await oauth2_scheme(request)

    if not token or not token.scopes or "my_permission" not in token.scopes:
        raise HTTPException(status_code=401, detail="Invalid or missing token")

    return Principal(
        id="user-id",
        roles=["user"],
        permissions={permission},
        extra={"email": "user@example.com"},
    )

# Add the Principal factory to the app
app.dependency_overrides[Principal] = principal_factory

# Add the OAuth2 middleware to the app
app.add_middleware(oauth2_middleware)

# Define a route that requires the permission
@app.post("/protected-route")
@PermissionRequired(permission)
async def protected_route(principal: Principal):
    return {"message": "Hello, {}".format(principal.id)}
```

**5. Use Principal to authorize a user using a custom authentication scheme**

```python
from fastapi import FastAPI, Request, HTTPException
from fastapi_principal import Principal, Permission, PermissionRequired
from fastapi_custom_auth import CustomAuthMiddleware

# Create the custom authentication middleware
custom_auth_middleware = CustomAuthMiddleware(
    auth_endpoint="https://example.com/auth",
    client_id="my_client_id",
    client_secret="my_client_secret",
)

# Create the FastAPI application
app = FastAPI()

# Define the permission
permission = Permission("my_permission")

# Define the Principal factory
async def principal_factory(request: Request) -> Principal:
    authorization_header = request.headers.get("Authorization")
    if not authorization_header or not authorization_header.startswith("Bearer "):
        raise HTTPException(status_code=401, detail="Missing or invalid authorization header")

    token = authorization_header.split(" ")[1]

    # Verify the token with the custom authentication endpoint
    response = await custom_auth_middleware.verify_token(token)
    if not response or not response.get("valid"):
        raise HTTPException(status_code=401, detail="Invalid token")

    return Principal(
        id="user-id",
        roles=["user"],
        permissions={permission},
        extra={"email": "user@example.com"},
    )

# Add the Principal factory to the app
app.dependency_overrides[Principal] = principal_factory

# Add the custom authentication middleware to the app
app.add_middleware(custom_auth_middleware)

# Define a route that requires the permission
@app.post("/protected-route")
@PermissionRequired(permission)
async def protected_route(principal: Principal):
    return {"message": "Hello, {}".format(principal.id)}
```

**6. Use Principal to authorize a user using a JWT**

```python
from fastapi import FastAPI, Request, HTTPException
from fastapi_principal import Principal, Permission, PermissionRequired
from jose import JWTError, jwt

# Create the FastAPI application
app = FastAPI()

# Define the permission
permission = Permission("my_permission")

# Define the Principal factory
async def principal_factory(request: Request) -> Principal:
    authorization_header = request.headers.get("Authorization")
    if not authorization_header or not authorization_header.startswith("Bearer "):
        raise HTTPException(status_code=401, detail="Missing or invalid authorization header")

    token = authorization_header.split(" ")[1]
    try:
        payload = jwt.decode(token, "my_secret", algorithms=["HS256"])
    except JWTError:
        raise HTTPException(status_code=401, detail="Invalid token")

```
