Skip to content
Back to Blog
1 min read

Securing AI Applications: Authentication and Authorization Patterns

I wrote “Securing AI Applications: Authentication and Authorization Patterns” to share practical, production-minded guidance on this topic.

Security Challenges for AI

AI applications face unique security concerns: protecting training data, controlling model access, securing inference endpoints, and preventing prompt injection. A defense-in-depth approach addresses each layer.

Implementing Secure Authentication

Use Microsoft Entra ID (Azure AD) for enterprise-grade authentication:

from fastapi import FastAPI, Depends, HTTPException, Security
from fastapi.security import OAuth2AuthorizationCodeBearer
from jose import jwt, JWTError
from pydantic import BaseModel
import httpx

app = FastAPI()

# Configure OAuth2 with Azure AD
oauth2_scheme = OAuth2AuthorizationCodeBearer(
    authorizationUrl=f"https://login.microsoftonline.com/{TENANT_ID}/oauth2/v2.0/authorize",
    tokenUrl=f"https://login.microsoftonline.com/{TENANT_ID}/oauth2/v2.0/token",
    scopes={"api://your-app-id/AI.Access": "Access AI endpoints"}
)

class TokenPayload(BaseModel):
    sub: str
    roles: list[str] = []
    groups: list[str] = []

async def get_current_user(token: str = Depends(oauth2_scheme)) -> TokenPayload:
    """Validate JWT token and extract user claims."""
    try:
        # Fetch Azure AD public keys
        async with httpx.AsyncClient() as client:
            jwks = await client.get(
                f"https://login.microsoftonline.com/{TENANT_ID}/discovery/v2.0/keys"
            )

        # Decode and validate token
        payload = jwt.decode(
            token,
            jwks.json(),
            algorithms=["RS256"],
            audience=f"api://{CLIENT_ID}",
            issuer=f"https://login.microsoftonline.com/{TENANT_ID}/v2.0"
        )

        return TokenPayload(
            sub=payload["sub"],
            roles=payload.get("roles", []),
            groups=payload.get("groups", [])
        )
    except JWTError as e:
        raise HTTPException(status_code=401, detail="Invalid token")

def require_role(required_role: str):
    """Dependency to enforce role-based access."""
    async def role_checker(user: TokenPayload = Depends(get_current_user)):
        if required_role not in user.roles:
            raise HTTPException(
                status_code=403,
                detail=f"Role '{required_role}' required"
            )
        return user
    return role_checker

@app.post("/api/chat")
async def chat_endpoint(
    request: ChatRequest,
    user: TokenPayload = Depends(get_current_user)
):
    """Standard AI chat endpoint - all authenticated users."""
    # Log access for audit trail
    audit_log.info(f"Chat access by user {user.sub}")
    return await process_chat(request, user)

@app.post("/api/admin/retrain")
async def retrain_model(
    user: TokenPayload = Security(require_role("AI.Admin"))
):
    """Admin-only endpoint for model retraining."""
    return await trigger_retraining()

Row-Level Security for RAG

Ensure users only retrieve documents they’re authorized to access:

class SecureRAGService:
    def __init__(self, search_client, llm_client):
        self.search_client = search_client
        self.llm_client = llm_client

    async def query(self, question: str, user: TokenPayload) -> str:
        """Execute RAG query with user's permission scope."""

        # Build security filter based on user's groups
        security_filter = " or ".join([
            f"allowed_groups/any(g: g eq '{group}')"
            for group in user.groups
        ])

        # Add public documents
        security_filter = f"({security_filter}) or is_public eq true"

        # Search with security filter
        results = self.search_client.search(
            search_text=question,
            filter=security_filter,
            top=5
        )

        # User only sees documents they can access
        context = [doc["content"] for doc in results]

        return await self.llm_client.generate(question, context)

Security for AI applications must be designed in from the start. Retrofitting security after deployment is significantly more difficult and error-prone.\n\n## Takeaways\n\nAdd a concise, personal takeaway and recommended next steps here.\n

Michael John Peña

Michael John Peña

Senior Data Engineer based in Sydney. Writing about data, cloud, and technology.