cicadel
Documentation

Authentication

Cicadel has one core accounts service and two explicit HTTP adapters. Browser applications use server-rendered HTML, server-side SCS sessions and CSRF checks. API clients can use the JSON bearer adapter. Both adapters consult the same PostgreSQL users, account sessions, recovery tokens, groups and permissions. Disabling an account, resetting its password or revoking its sessions affects both adapters. A browser never receives the account bearer token in HTML or JSON.

Ask your agent

text
Read https://cicadel.fauzaanu.com/en/dev/topics/authentication/index.md.
Add browser sign-in to my application using the accounts starter or adapter.
Use PostgreSQL sessions, CSRF protection and verified recovery addresses.
Show the registration and route protection code. Test sign-in, sign-out,
and rejection of revoked sessions; keep secrets outside source code.

Create the starter

From the framework checkout:

sh
go build -o bin/cicadel ./cmd/cicadel
./bin/cicadel startproject /tmp/myapp example.com/myapp
cd /tmp/myapp
go mod edit -replace=github.com/fauzaanu/cicadel=/absolute/path/to/Cicadel
go mod edit -replace=github.com/fauzaanu/cicadel/contrib/accounts=/absolute/path/to/Cicadel/contrib/accounts
go mod edit -replace=github.com/fauzaanu/cicadel/contrib/formsets=/absolute/path/to/Cicadel/contrib/formsets
go mod edit -replace=github.com/fauzaanu/cicadel/contrib/migrations=/absolute/path/to/Cicadel/contrib/migrations
go mod edit -replace=github.com/fauzaanu/cicadel/contrib/querygen=/absolute/path/to/Cicadel/contrib/querygen
go mod tidy
export DATABASE_URL='postgres://USER:PASSWORD@localhost/myapp?sslmode=disable'
export CICADEL_DEBUG=true
export CICADEL_SECURE_COOKIES=false
go run manage.go migrate
CICADEL_USER_PASSWORD='a local account password' go run manage.go createuser owner@example.com
go run manage.go runserver

Use an email address whose ownership you have verified before provisioning the account. This starter treats the stored username as that verified recovery address. Requests cannot supply a separate delivery address. There is no public registration endpoint or administrator panel. The service’s Create API remains available for application-owned provisioning and invitation workflows.

The accounts module has no published release yet. The commands above use local checkout paths; commit your resolved Go dependencies and replace machine-specific paths before distributing the application. startproject always includes accounts, formsets and the standard migration workflow; runtime commands require PostgreSQL. The old --accounts spelling is a compatibility alias for the same starter.

Screens and actions

The default prefix is /accounts; accounts.Pages.Prefix can change it.

RouteGETPOST
/accountsSigned-in account and session actions—
/accounts/loginLogin formRotate session and sign in
/accounts/recoverRecovery formDeliver a reset link to the verified destination
/accounts/resetReset form with tokenConsume the token once and replace the password
/accounts/change-passwordCurrent/new password formReplace password and revoke all sessions
/accounts/logout—Revoke current account session and destroy its cookie session
/accounts/revoke—Revoke all account sessions and sign out
/accounts/style.cssEmbedded compiled stylesheet—

To customize the screens, compose your own pages with contrib/accounts/accountui.

Integrate an existing application

In your project setup, create the service and browser adapter, then register the returned app:

go
service, err := accounts.New(accounts.Options{
    DB: db,
    DeliverRecovery: DeliverRecovery,
})
if err != nil {
    return err
}
browser, err := service.Browser(security.NewSessions(store, true))
if err != nil {
    return err
}
authApp, err := browser.HTMLApp(accounts.Pages{
    Brand: "My application",
    Logger: logger,
})
if err != nil {
    return err
}
installed = append(installed, authApp)

This setup fragment uses your PostgreSQL db, shared session store, logger, recovery callback and existing []cicadel.App. Pass installed to the project’s cicadel.New call. Register the adapter once and run migrate before serving. The generated accounts starter includes the full setup in project/application.go.

Protect another app’s handler with the browser adapter:

go
protected := browser.Middleware(browser.RequireLogin(http.HandlerFunc(dashboard)))
route := urls.Path("GET", "/dashboard", "dashboard:index", protected.ServeHTTP)

Add route to that app’s routes. Import net/http and github.com/fauzaanu/cicadel/urls; dashboard is your handler. Check object-level permissions inside it.

HTMLApp owns LoadAndSave → CSRF → account-resolution middleware for its routes. Do not wrap those routes with those same middleware again. For another app’s protected routes, apply browser.Middleware then browser.RequireLogin, and use accounts.UserFromContext inside handlers. RequireLogin checks a freshly resolved account, rather than only a stored SCS user ID. Object permissions still require explicit application policy and scoped database queries.

The starter uses PostgreSQL accounts_browser_sessions through SCS’s configurable table name. Migration 002 adds the table without rewriting the existing accounts history. A custom store may also be supplied. Sessions are HttpOnly, SameSite=Lax, secure by default, rotated on login and cleared at logout. Account expiry and revocation are checked on every browser request. SCS expiry can end a session before the associated account token expires; accounts:cleanup removes expired tokens. Browser forms are bounded to 8 KiB and all unsafe methods require CSRF.

For API-only clients use service.HTTPApp(prefix) and service.Middleware with explicit Authorization: Bearer …. Register either adapter once under the accounts app name. If a host needs both, combine their routes into that one app and scope cookie middleware to the HTML routes; never apply cookie CSRF middleware to a bearer-only API by accident.

Recovery delivery and deployment

Configure these starter environment variables:

VariablePurpose
CICADEL_PUBLIC_URLHTTPS origin used to construct reset links
CICADEL_MAIL_FROMSender mailbox
CICADEL_SMTP_ADDRESSSMTP host:port with STARTTLS
CICADEL_SMTP_USERNAME, CICADEL_SMTP_PASSWORDOptional SMTP credentials
CICADEL_LOG_FORMAT, CICADEL_LOG_LEVELJSON/text format and log threshold

project.DeliverRecovery is the application-owned callback. It sends to the stored verified address, constructs a local reset route using the configured origin and passes the token only to the mail transport. Known and unknown users receive the same recovery response. Delivery errors are logged without tokens, addresses or server response text. Missing delivery configuration is handled without revealing whether a username exists. Passwords must contain 12–72 bytes; applications may add their own password policy.

Use HTTPS and secure cookies, configure allowed hosts, apply gateway rate limits to login/recovery endpoints and schedule manage.go accounts:cleanup. Never log query strings on reset routes at the proxy. Reset pages send no-referrer, no-store and a restrictive content security policy. See email, logging and operations for configuration details.

↑

Type to search this version.