Skip to content

Displaying one-time secrets

A common pattern in admin panels is generating a secret (API key, token, etc.) that is shown once right after creation and never again.

The solution

Call Secret.reveal_once(request, value) from after_model_change. SQLAdmin will skip the usual redirect, re-render the create/edit page, and display the value in a one-time modal rendered by layout.html.

The secret lives only on request.state - it is never written to the session or sent as a cookie, so it cannot leak across requests.

import secrets
from sqladmin import ModelView, Secret


class ApiKeyAdmin(ModelView, model=ApiKey):
    async def on_model_change(self, data, model, is_created, request):
        if is_created:
            # Generate the raw value and store the hash on the model
            # *before* the row is committed.
            raw_secret = secrets.token_urlsafe(32)
            model.secret_hash = hash_secret(raw_secret)
            request.state._raw_secret = raw_secret

    async def after_model_change(self, data, model, is_created, request):
        raw_secret = getattr(request.state, "_raw_secret", None)
        if raw_secret:
            Secret.reveal_once(
                request,
                value=raw_secret,
                title="Your API key",
                label="Copy this value now, it will not be shown again.",
            )

Secret.reveal_once is also usable from a BaseView. Call it before returning a TemplateResponse and the modal will render through layout.html. The built-in create/edit handlers stamp anti-cache headers on the response automatically; custom views must do so explicitly:

response = await self.templates.TemplateResponse(request, "your_template.html", context)
Secret.apply_no_store_headers(response)
return response

Custom rendering

If you need full control over the response (custom template, redirect to a wizard step, file download, etc.), return a Starlette Response from after_model_change instead - see Controlling the response with after_model_change.