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 ¶
- Variables
- type Account
- type Accounts
- func (s *Accounts) Delete(c *gin.Context) error
- func (s *Accounts) Get(ctx context.Context, id string) (Account, error)
- func (s *Accounts) Mount(r gin.IRouter, layout ui.Layout)
- func (s *Accounts) OnDelete(hook func(ctx context.Context, tx *sql.Tx, accountID string) error)
- func (s *Accounts) Pages(layout ui.Layout) *Pages
- func (s *Accounts) RequireSignIn(c *gin.Context)
- type Config
- type Pages
- func (p *Pages) Delete(c *gin.Context)
- func (p *Pages) DeleteForm(c *gin.Context)
- func (p *Pages) Deleted(c *gin.Context)
- func (p *Pages) EmailChanged(c *gin.Context)
- func (p *Pages) Logout(c *gin.Context)
- func (p *Pages) MountProfile(settings gin.IRouter)
- func (p *Pages) Settings(c *gin.Context)
- func (p *Pages) Unverified(c *gin.Context)
- type Paths
Constants ¶
This section is empty.
Variables ¶
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") )
var ErrNotFound = errors.New("accounts: account not found")
ErrNotFound means no account has the given ID.
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.
type Accounts ¶
type Accounts struct {
// contains filtered or unexported fields
}
Accounts is the accounts module.
func New ¶
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 ¶
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) Mount ¶
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 ¶
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 ¶
Pages returns the account pages rendered in layout. It panics without an identity provider, which is a programming error.
func (*Accounts) RequireSignIn ¶
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 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 ¶
Delete deletes the account once the user typed DELETE after a recent sign-in.
func (*Pages) DeleteForm ¶
DeleteForm asks to confirm the deletion.
func (*Pages) Deleted ¶
Deleted confirms a deletion. With "unfinished", it says that the deletion of the address's account has not finished yet.
func (*Pages) EmailChanged ¶
EmailChanged confirms an email change, after which the user signs in again.
func (*Pages) MountProfile ¶
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) Unverified ¶
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.