Skip to content

Standalone Auth Micro-Service

create_auth_app() deploys the Kirak auth module as a standalone FastAPI application with only /auth/* routes – no CRUD engine, no model-driven routes. Use this when you want authentication as a dedicated micro-service.


Scenario Use
All-in-one API with auth + CRUD create_kirak_app()
Auth service that other APIs call create_auth_app()
Integrate auth into an existing FastAPI app create_app() + Kirak()

main_auth.py
from dotenv import load_dotenv
load_dotenv()
from kirak import create_auth_app
def on_auth_ready(auth):
# auth is the Auth module instance -- not the full Kirak facade
@auth.hook("after_login")
async def add_org_data(result):
if result.get("status") == "success":
# Add organisation data to the login response (the tokens are already signed)
pass
return result
app = create_auth_app(
models_path="./models/", # optional -- your own models; the auth tables are always built in
on_auth_ready=on_auth_ready,
)
Terminal window
uvicorn main_auth:app --reload --port 8001

Parameter Default Description
models_path built-in auth_models.json Path to a models file or directory with the service’s own models. They are merged with the built-in auth tables, which are loaded last and silently override a model of the same name (users, auth_tokens, …), so the auth tables cannot be redefined or extended. If omitted, only the built-in auth tables are used.
title "Kirak Auth Service" FastAPI app title.
description "Standalone authentication service powered by Kirak" FastAPI app description.
version "1.0.0" API version.
enable_cors False Enable CORS middleware.
cors_origins [] Allowed origins.
auth_prefix None (/auth) URL path of the auth routes; replaces /auth. Pass "/api/v1/auth" to mount at /api/v1/auth/.... The Kirak client SDK calls the default /auth routes, so keep the default for SDK clients.
middlewares [] Extra ASGI middleware as (Class, options) pairs.
on_startup None async (app) callback – runs before auth initialises.
on_auth_ready None async (auth) callback – register hooks here. Note: receives the Auth module, not the Kirak facade.
on_shutdown None async (app) callback – runs after auth disconnects.

create_kirak_app() create_auth_app()
CRUD routes [x] Generated for all models [ ] None
Auth routes [x] /auth/* (or auth_prefix) [x] /auth/* (or auth_prefix)
on_kirak_ready callback (kirak) – receives Kirak facade –
on_auth_ready callback – (auth) – receives Auth module
Modules (notifications, etc.) [x] Via modules=[] [ ] Not supported
GraphQL [x] Per model [ ] None
include_crud=False Not applicable Always (CRUD excluded)

When using on_auth_ready, the argument is the Auth module instance – use auth.hook(), auth.on(), not kirak.auth.hook():

def on_auth_ready(auth):
@auth.hook("after_register")
async def send_welcome(result):
# auth module available as `auth`, not `kirak.auth`
# No kirak.notifications available here -- call your notification service directly
return result

The auth micro-service has its own database connection and runs independently. Other services in your infrastructure call it over HTTP:

+-----------------+ POST /auth/login +------------------+
| Mobile App | ---------------------------> | Auth Service |
+-----------------+ | :8001 |
| (kirak auth) |
+-----------------+ Authorization: Bearer ... +------------------+
| API Service | --------------------------> Verify token via:
| :8000 | - Shared KIRAK_AUTH_JWT_SECRET_KEY
| (kirak full) | - OR /auth/me endpoint
+-----------------+

Both services must share KIRAK_AUTH_JWT_SECRET_KEY and the same jwt_algorithm (kirak.json auth.jwt_algorithm) for tokens minted by the auth service to be verifiable by the API service.


API services can verify tokens from the auth micro-service in two ways:

1. Decode locally (recommended – no network call):

from kirak.auth.utils.jwt import decode_token
payload = decode_token(token)
if payload:
user_id = payload.get("sub")
role = payload.get("role")

Both services must use the same KIRAK_AUTH_JWT_SECRET_KEY.

2. Call the auth service:

GET http://auth-service:8001/auth/me
Authorization: Bearer eyJhbGc...

docker-compose.yml
services:
auth:
image: my-app/auth
command: uvicorn main_auth:app --host 0.0.0.0 --port 8001
environment:
- DB_PASSWORD=${DB_PASSWORD} # database name and host are in each service's kirak.json
- KIRAK_AUTH_JWT_SECRET_KEY=${JWT_SECRET}
- KIRAK_AUTH_VERIFICATION_KEY=${FERNET_KEY}
ports:
- "8001:8001"
api:
image: my-app/api
command: uvicorn main:app --host 0.0.0.0 --port 8000
environment:
- DB_PASSWORD=${DB_PASSWORD}
- KIRAK_AUTH_JWT_SECRET_KEY=${JWT_SECRET} # same key as auth service
ports:
- "8000:8000"