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

identity

package
v0.21.0 Latest Latest
Warning

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

Go to latest
Published: Oct 29, 2026 License: AGPL-3.0 Imports: 20 Imported by: 0

Documentation

Overview

Package identity holds the external identities Atlas users link and the delegated connections they authorize, and brokers the short-lived credentials those connections yield (ADR-0475 §3, §4).

Four concepts stay apart here. An Atlas principal is the user store's. An ExternalIdentity is one account at a provider, bound by issuer, tenant and stable subject — never by e-mail. A Connection is a principal's authorization for Atlas to act as that identity, through the Workers its owner allowed. Its credential, a refresh token, is a vault secret under a reserved name and never part of the connection record, a response, a log line or an event.

Design-time state: two sidecar stores owned by the run loop. Nothing here reaches the event log; the decisions made with a connection do, through the enforcement point.

Index

Constants

View Source
const (
	StatusActive         = "active"
	StatusReauthRequired = "reauth_required"
	StatusRevoked        = "revoked"
)

Connection states. They are authz's words, so the decision reads them as stored.

View Source
const AuthCodePKCE = "authorization_code_pkce"

AuthCodePKCE is how a delegated connection was authorized: the browser's authorization-code flow with PKCE, at the provider.

View Source
const ProviderMicrosoft = "microsoft"

Providers this build can link.

Variables

View Source
var (
	ErrNotFound        = errors.New("identity: no such connection")
	ErrNotOwner        = errors.New("identity: only the connection's owner may do that")
	ErrRevoked         = errors.New("identity: the connection is revoked")
	ErrInactive        = errors.New("identity: the connection is not active")
	ErrLinkedElsewhere = errors.New("identity: that external account is linked to another Atlas user")
	ErrUnknownWorker   = errors.New("identity: no configured Worker has that name")
	ErrAmbiguous       = errors.New("identity: more than one connection of the owner allows this Worker")
	// ErrInvalidGrant is a provider refusing a refresh token: revoked, expired, or
	// consent withdrawn. Only a person signing in again can mend it.
	ErrInvalidGrant = errors.New("identity: the provider refused the refresh token")
)

Errors a caller distinguishes.

Functions

This section is empty.

Types

type Connection

type Connection struct {
	ID         string `json:"id"`
	OwnerID    string `json:"ownerId"`
	Provider   string `json:"provider"`
	IdentityID string `json:"identityId"`
	// IdentityKey is the identity's Key, kept here so a decision can name whom it ran
	// as without reading the identity store.
	IdentityKey string   `json:"identityKey"`
	AuthMethod  string   `json:"authMethod"`
	TenantID    string   `json:"tenantId,omitempty"`
	Scopes      []string `json:"scopes"`
	// AllowedWorkers are the configured Workers that may act through this
	// connection. Empty allows none: consenting to a sign-in is not consenting to
	// every Worker.
	AllowedWorkers        []string `json:"allowedWorkers"`
	Status                string   `json:"status"`
	CreatedAt             int64    `json:"createdAt"`
	UpdatedAt             int64    `json:"updatedAt"`
	LastInteractiveAuthAt int64    `json:"lastInteractiveAuthAt"`
	LastRefreshAt         int64    `json:"lastRefreshAt,omitempty"`
	RevokedAt             int64    `json:"revokedAt,omitempty"`
	RevokedBy             string   `json:"revokedBy,omitempty"`
	RevokeReason          string   `json:"revokeReason,omitempty"`
}

Connection is the public half of a delegated connection.

type ExternalIdentity

type ExternalIdentity struct {
	ID       string `json:"id"`
	UserID   string `json:"userId"`
	Provider string `json:"provider"`
	Issuer   string `json:"issuer"`
	TenantID string `json:"tenantId,omitempty"`
	// Subject is the provider's stable identifier for the person: Microsoft's object
	// id (oid), which unlike the pairwise sub identifies the person across
	// applications.
	Subject string `json:"subject"`
	// Username and DisplayName are what the provider called the account at the last
	// sign-in. Shown, never matched: an e-mail address can be reassigned.
	Username            string `json:"username,omitempty"`
	DisplayName         string `json:"displayName,omitempty"`
	LinkedAt            int64  `json:"linkedAt"`
	LastAuthenticatedAt int64  `json:"lastAuthenticatedAt"`
}

ExternalIdentity is one account at a provider that an Atlas user linked.

func (ExternalIdentity) Key

func (x ExternalIdentity) Key() string

Key is the identity's name in a decision's ExecutedAs.

type LinkOption

type LinkOption struct {
	Provider string `json:"provider"`
	Start    string `json:"start"`
}

LinkOption is one provider a person can link an account with.

type LinkRequest

type LinkRequest struct {
	UserID       string
	Provider     string
	Issuer       string
	TenantID     string
	Subject      string
	Username     string
	DisplayName  string
	Scopes       []string
	RefreshToken string
}

LinkRequest is a verified sign-in at a provider: every field comes out of an ID token whose signature, issuer, audience, nonce and lifetime were checked, or out of the token response that accompanied it.

type Refresher

type Refresher func(ctx context.Context, c Connection, refreshToken string) (Tokens, error)

Refresher asks the provider for an access token with a refresh token. It returns ErrInvalidGrant (wrapped or not) when the provider refused the token itself.

type Secrets

type Secrets interface {
	Get(name string) (string, bool, error)
	Set(name, value string) (vault.Meta, error)
	Delete(name string) error
}

Secrets is the vault, as this service uses it. Every call is made on the run loop.

type Service

type Service struct {

	// Limits are the installation's resource budgets. New sets them to
	// [limits.Default]; the server overwrites them with its own.
	Limits limits.Limits
	// contains filtered or unexported fields
}

Service is the identity area. Build it with New.

func New

func New(loop *runloop.Loop, stores *Stores, secrets Secrets, refresh Refresher,
	workerKnown func(name string) bool, now func() time.Time) *Service

New builds the service. refresh asks the provider for tokens; workerKnown says whether a configured Worker of that name exists (it is called on the loop).

func (*Service) AccessToken

func (s *Service) AccessToken(ctx context.Context, id string) (string, time.Time, error)

AccessToken is the credential broker: a short-lived access token for an active connection. Atlas is the only holder of the refresh token, refreshes one connection at a time, and writes a rotated refresh token to the vault before releasing the access token that came with it — so a crash can lose an access token, never leave the vault holding a superseded refresh token. A connection revoked while its refresh was in flight keeps its revocation: the rotated token is not written back and nothing is released.

The caller is the enforcement point, after a durably recorded Permit; nothing else may call this.

func (*Service) ConnectionFor

func (s *Service) ConnectionFor(ownerID, provider, worker string) (Connection, bool, error)

ConnectionFor chooses the connection a Worker acts through for an owner: their one connection of that provider that allows the Worker. None is "no connection"; two is ambiguous, and ambiguity chooses nothing rather than guessing whose account acts. Revoked and inactive connections are returned when they are the only candidate, so the decision can say why it refused.

func (*Service) ForOwner

func (s *Service) ForOwner(userID string) ([]ExternalIdentity, []Connection)

ForOwner lists a user's identities and connections, newest first.

func (*Service) ForgetAccessTokens added in v0.21.0

func (s *Service) ForgetAccessTokens()

ForgetAccessTokens drops every cached access token, so the next release for any connection asks the provider again, under whatever app registration is configured by then. The server calls it whenever linking is set up, changed or removed: a token obtained under the previous setup must not be handed out for up to an hour after it. A release already in flight is the check-then-act window §13 accepts for a revocation, and ends the same way: the next one is decided afresh.

func (*Service) Get

func (s *Service) Get(id string) (Connection, bool, error)

Get reads one connection.

func (*Service) HandleMine

func (s *Service) HandleMine(w http.ResponseWriter, r *http.Request)

HandleMine lists the caller's own identities and connections.

func (*Service) HandleOfUser

func (s *Service) HandleOfUser(w http.ResponseWriter, r *http.Request)

HandleOfUser lists one user's identities and connections, for an administrator answering "what can act as this person".

func (*Service) HandleRevoke

func (s *Service) HandleRevoke(isAdmin func(*httpapi.Principal) bool) http.HandlerFunc

HandleRevoke withdraws a connection. Its owner may, and so may an administrator.

func (*Service) HandleSetWorkers

func (s *Service) HandleSetWorkers(w http.ResponseWriter, r *http.Request)

HandleSetWorkers replaces the Workers allowed to act through a connection. Only the owner may: it is their consent.

func (s *Service) Link(req LinkRequest) (Connection, error)

Link records a verified sign-in: the identity, and a connection authorized by it. Linking an account already linked to this user re-authenticates its connection; one linked to somebody else is refused. The credential is stored before the connection says it is active, so an active connection always has one.

func (*Service) Linkable added in v0.21.0

func (s *Service) Linkable() []LinkOption

Linkable is what SetLinkable last said, never nil.

func (*Service) Revoke

func (s *Service) Revoke(id, by string, admin bool, reason string) (Connection, error)

Revoke withdraws a connection for good: the credential is deleted and the record says who withdrew it and why. Its owner may revoke it, and so may an administrator — taking access away is never a person's alone to block.

func (*Service) SetAllowedWorkers

func (s *Service) SetAllowedWorkers(id, by string, workers []string) (Connection, error)

SetAllowedWorkers replaces the Workers that may act through a connection. Only its owner consents to that: an administrator who could add a Worker here could have any Worker act as anybody.

func (*Service) SetLinkable

func (s *Service) SetLinkable(options ...LinkOption)

SetLinkable says which providers this server links accounts with. The server sets it while it is built and again whenever an administrator sets up or removes linking; none clears it.

func (*Service) Unrevoked added in v0.21.0

func (s *Service) Unrevoked(provider string) map[string]int

Unrevoked counts the connections of one provider that are not revoked, by tenant: the ones whose owners would have to sign in again, or could not act at all, if the app registration they were authorized through changed.

type Stores

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

Stores are the two sidecar stores.

func OpenStores

func OpenStores(dir string) (*Stores, error)

OpenStores opens the stores under dir.

type Tokens

type Tokens struct {
	AccessToken  string
	RefreshToken string // empty when the provider does not rotate
	ExpiresIn    int64  // seconds
	Scope        string
}

Tokens is a provider's answer to a refresh.

Jump to

Keyboard shortcuts

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