Help us shape the future of Go! Take the 2026 Go Developer Survey

accounts

package
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 12, 2026 License: Apache-2.0 Imports: 21 Imported by: 0

Documentation

Overview

Package accounts maps identities to local accounts, protects signed-in routes and deletes accounts.

A sign-in finds its account by the identity provider and subject. An identity the app has not seen joins the account that has its verified email address, whichever provider it comes from, or gets a new account. Unverified identities cannot sign in.

Deleting an account deletes the identity at the provider first, then removes local data in one transaction that modules and the app join through OnDelete.

templ: version: v0.3.1070

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrNotDeleted means the identity provider did not confirm the deletion. Nothing
	// was deleted, and the user can try again.
	ErrNotDeleted = errors.New("accounts: the identity provider did not delete the account")
	// ErrCleanupPending means the identity was deleted at the provider but the local
	// data was not. An operator must run accounts delete-local for the account; if its
	// address signs up again first, the sign-up finishes a deletion the provider's
	// confirmation was recorded for.
	ErrCleanupPending = errors.New("accounts: local cleanup is pending")
)
View Source
var ErrNotFound = errors.New("accounts: account not found")

ErrNotFound means no account has the given ID.

View Source
var Migrations = app.Migrations{Namespace: "accounts", Files: sub(migrationFiles, "migrations")}

Migrations create the accounts tables. List them before the other modules' in app.Config.Migrations.

Functions

This section is empty.

Types

type Account

type Account struct {
	ID string
	// Email is the account's primary address. One of the account's identities verified
	// it, unless every identity has since moved to an address the provider has not
	// verified or that another account has.
	Email     string
	CreatedAt time.Time
}

Account is a local account.

func Current

func Current(c *gin.Context) Account

Current returns the signed-in account. It panics on routes without RequireSignIn, which is a programming error.

type Accounts

type Accounts struct {
	// contains filtered or unexported fields
}

Accounts is the accounts module.

func New

func New(a *app.App, idp identity.Provider, cfg Config) (*Accounts, error)

New returns the accounts module for idp. It registers the accounts delete-local command.

A process that only needs account IDs, such as an API gateway that authenticates with API keys, passes a nil idp: it holds no sign-in configuration, and RequireSignIn, Mount and Delete are unavailable.

func (*Accounts) Delete

func (s *Accounts) Delete(c *gin.Context) error

Delete deletes the signed-in account: first the identity at the provider, then, once the provider confirms, the local data in one transaction with every OnDelete hook. It continues if the browser disconnects, and clears the browser session afterwards.

The two systems are not atomic. The account is marked before the provider is asked, the mark is cleared if the provider refuses, and the provider's confirmation is recorded before the local data is deleted. If the local transaction fails after the provider deleted the identity, Delete logs the account ID and returns ErrCleanupPending.

func (*Accounts) Get

func (s *Accounts) Get(ctx context.Context, id string) (Account, error)

Get returns an account by ID.

func (*Accounts) Mount

func (s *Accounts) Mount(r gin.IRouter, layout ui.Layout)

Mount adds every account page to r, usually the app's engine, at Config.Paths:

  • POST Logout signs out and continues to a local "next" path, or "/".
  • GET Unverified asks an identity without a verified email to confirm it.
  • GET Settings shows the email address, the provider's profile UI when it has one, signing out and account deletion. The profile UI's routes go under it.
  • GET and POST Delete confirm and delete the account.
  • GET Deleted and EmailChanged confirm those changes after the session ended.

The settings and delete pages use RequireSignIn. When r is a group, every path must be under its prefix. To serve one of the pages yourself, register the others with Pages instead.

func (*Accounts) OnDelete

func (s *Accounts) OnDelete(hook func(ctx context.Context, tx *sql.Tx, accountID string) error)

OnDelete adds a hook to account deletion. Hooks run in the order they were added, inside the transaction that deletes the account, so an error rolls everything back. Use it for personal data that a foreign key with ON DELETE CASCADE cannot remove.

func (*Accounts) Pages

func (s *Accounts) Pages(layout ui.Layout) *Pages

Pages returns the account pages rendered in layout. It panics without an identity provider, which is a programming error.

func (*Accounts) RequireSignIn

func (s *Accounts) RequireSignIn(c *gin.Context)

RequireSignIn protects browser routes that need a signed-in user. It checks CSRF on state-changing requests, because sign-in is cookie-based, then validates the session and finds the account, creating it on first sign-in. Visitors without a session are sent to the login page, and identities without a verified email to a page that asks them to confirm it. Responses are marked not to be stored.

A request it stops without a redirect gets only a status, not yet written, so middleware that runs before it can render an error page after c.Next.

type Config

type Config struct {
	Paths Paths
}

Config configures the module.

type Pages

type Pages struct {
	// contains filtered or unexported fields
}

Pages are the account pages' handlers, for apps that register some of them themselves. Register each at its path in Config.Paths: the pages link to each other there. Settings, DeleteForm and Delete need RequireSignIn, and Logout needs web.CSRF.

func (*Pages) Delete

func (p *Pages) Delete(c *gin.Context)

Delete deletes the account once the user typed DELETE after a recent sign-in.

func (*Pages) DeleteForm

func (p *Pages) DeleteForm(c *gin.Context)

DeleteForm asks to confirm the deletion.

func (*Pages) Deleted

func (p *Pages) Deleted(c *gin.Context)

Deleted confirms a deletion. With "unfinished", it says that the deletion of the address's account has not finished yet.

func (*Pages) EmailChanged

func (p *Pages) EmailChanged(c *gin.Context)

EmailChanged confirms an email change, after which the user signs in again.

func (*Pages) Logout

func (p *Pages) Logout(c *gin.Context)

Logout signs out and continues to a local "next" path, or "/".

func (*Pages) MountProfile

func (p *Pages) MountProfile(settings gin.IRouter)

MountProfile adds the provider's profile UI routes, if it has any, to settings: a group at the settings path that uses RequireSignIn. The Settings page embeds the UI.

func (*Pages) Settings

func (p *Pages) Settings(c *gin.Context)

Settings is the settings page.

func (*Pages) Unverified

func (p *Pages) Unverified(c *gin.Context)

Unverified asks an identity without a verified email to confirm its address.

type Paths

type Paths struct {
	Login        string // "/login", the identity provider's sign-in page
	Logout       string // "/logout"
	Unverified   string // "/auth/email-unverified"
	Settings     string // "/account/settings"
	Delete       string // "/account/delete"
	Deleted      string // "/account/deleted"
	EmailChanged string // "/account/email-changed"
}

Paths are where the account pages live, as URL paths. RequireSignIn and the pages use them for every redirect and link. A zero field takes the default shown.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL