Skip to content

The protected decorator

The protected decorator is web framework agnostic and can be used to apply automatic api key verification to your endpoints.

Check out how easily you can protect your endpoints using protected!


FastAPI

Dependencies

Example

import os
from typing import Any, Dict, Optional

import fastapi
import unkey
import uvicorn

app = fastapi.FastAPI()


def key_extractor(*args: Any, **kwargs: Any) -> Optional[str]:
    if isinstance(auth := kwargs.get("authorization"), str):
        return auth.split(" ")[-1]

    return None


@app.get("/protected")
@unkey.protected(os.environ["UNKEY_API_ID"], key_extractor)
async def protected_route(
    *,
    authorization: str = fastapi.Header(None),
    unkey_verification: Any = None,
) -> Dict[str, Optional[str]]:
    assert isinstance(unkey_verification, unkey.ApiKeyVerification)
    assert unkey_verification.valid
    print(unkey_verification.owner_id)
    return {"message": "protected!"}


if __name__ == "__main__":
    uvicorn.run(app)

Flask

Dependencies

Example

import os
from typing import Any, Optional

import flask
import unkey
from flask.typing import ResponseReturnValue

app = flask.Flask(__name__)


def key_extractor(*args: Any, **kwargs: Any) -> Optional[str]:
    auth = flask.request.headers.get("authorization")
    if isinstance(auth, str):
        return auth.split(" ")[-1]

    return None


@app.get("/protected")
@unkey.protected(os.environ["UNKEY_API_ID"], key_extractor)
async def protected_route(
    *, unkey_verification: unkey.ApiKeyVerification
) -> ResponseReturnValue:
    assert unkey_verification.valid
    print(unkey_verification.owner_id)
    return {"message": "protected!"}


if __name__ == "__main__":
    app.run(port=8000, debug=True)

Quart

Dependencies

Example

import os
from typing import Any, Optional

import quart
import unkey

app = quart.Quart(__name__)


def key_extractor(*args: Any, **kwargs: Any) -> Optional[str]:
    auth = quart.request.headers.get("authorization")
    if isinstance(auth, str):
        return auth.split(" ")[-1]

    return None


@app.get("/protected")
@unkey.protected(os.environ["UNKEY_API_ID"], key_extractor)
async def protected_route(
    *, unkey_verification: unkey.ApiKeyVerification
) -> quart.Response:
    assert unkey_verification.valid
    print(unkey_verification.owner_id)
    return quart.jsonify(message="protected!")


if __name__ == "__main__":
    app.run(port=8000, debug=True)

Django

Dependencies

Example

import os
import sys
from typing import Any, Dict, Optional

import unkey
from django.conf import settings
from django.urls import path
from django.core.management import execute_from_command_line
from django.http import JsonResponse, HttpRequest

settings.configure(
    DEBUG=True,
    ROOT_URLCONF=sys.modules[__name__],
)


def key_extractor(*args: Any, **kwargs: Any) -> Optional[str]:
    if args and (auth := args[0].headers.get("authorization")):
        if isinstance(auth, str):
            return auth.split(" ")[-1]

    return None


def on_invalid_key(
    data: Dict[str, Optional[str]],
    verification: Optional[unkey.ApiKeyVerification],
) -> JsonResponse:
    response = {"error": "Key is invalid", **data}

    if verification:
        response["verification"] = verification.to_dict()

    return JsonResponse(response)


def on_exc(exc: Exception) -> JsonResponse:
    print(exc, file=sys.stderr)
    return JsonResponse({"error": "An unexpected error occurred"})


@unkey.protected(
    os.environ["UNKEY_API_ID"], key_extractor, on_invalid_key, on_exc
)
def protected_route(
    request: HttpRequest, *, unkey_verification: unkey.ApiKeyVerification
) -> JsonResponse:
    assert unkey_verification.valid
    print(unkey_verification.owner_id)
    return JsonResponse({"message": "protected!"})


urlpatterns = [path("protected", protected_route)]


if __name__ == "__main__":
    execute_from_command_line(sys.argv)