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

organization

package
v0.1.0-alpha.9 Latest Latest
Warning

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

Go to latest
Published: Sep 23, 2026 License: MIT Imports: 17 Imported by: 0

Documentation

Overview

Package organization provides optional PostgreSQL/SQLite tenant membership and session context.

Index

Constants

View Source
const (
	InviteOperation            plugin.Operation = "organization.invite"
	AcceptOperation            plugin.Operation = "organization.accept"
	RevokeInvitationOperation  plugin.Operation = "organization.invitation.revoke"
	RemoveMemberOperation      plugin.Operation = "organization.member.remove"
	TransferOwnershipOperation plugin.Operation = "organization.ownership.transfer"
	InvitationLifetime                          = 24 * time.Hour
)
View Source
const CreateOperation plugin.Operation = "organization.create"
View Source
const ID = "organization"
View Source
const RenameOperation plugin.Operation = "organization.rename"
View Source
const SelectOperation plugin.Operation = "organization.select"

Variables

This section is empty.

Functions

func Contract

func Contract() plugin.Definition

func DeprovisionMember

func DeprovisionMember(tx storage.Tx, id, userID string) error

DeprovisionMember removes userID's membership of organization id inside a trusted transaction that already holds that user's core lock. It is for plugins that remove members on the organization's behalf, such as SCIM deprovisioning. The owner is never removed (sigil.ErrForbidden): ownership must be transferred first. Removing a non-member succeeds without change. Like an administrative RemoveMember, it withdraws the organization's outstanding invitations, which may be addressed to the account's former email identities, and active selections cascade.

func PruneExpired

func PruneExpired(ctx context.Context, store storage.Store, before time.Time, limit int) (int64, error)

PruneExpired removes at most limit (1..1000) expired invitations. The cutoff is clamped to database time and persisted ownership permits offline cleanup.

Types

type Invitation

type Invitation struct {
	ID             string    `json:"id"`
	OrganizationID string    `json:"organizationId"`
	Email          string    `json:"email"`
	ExpiresAt      time.Time `json:"expiresAt"`
}

Invitation contains public metadata. IssuedInvitation.Token is returned only after commit; the host delivers it to Email without logging or URL analytics.

type IssuedInvitation

type IssuedInvitation struct {
	Invitation Invitation   `json:"invitation"`
	Token      sigil.Secret `json:"-"`
}

type Membership

type Membership struct {
	OrganizationID string    `json:"organizationId"`
	UserID         string    `json:"userId"`
	Role           Role      `json:"role"`
	CreatedAt      time.Time `json:"createdAt"`
}

type Organization

type Organization struct {
	ID        string    `json:"id"`
	Name      string    `json:"name"`
	CreatedAt time.Time `json:"createdAt"`
}

type Permission

type Permission string

Permission names the library's organization actions, not arbitrary application resources.

const (
	PermissionRead              Permission = "read"
	PermissionRename            Permission = "rename"
	PermissionInvite            Permission = "invite"
	PermissionRevokeInvitation  Permission = "invitation.revoke"
	PermissionRemoveMember      Permission = "member.remove"
	PermissionChangeRole        Permission = "member.role.change"
	PermissionTransferOwnership Permission = "ownership.transfer"
	// PermissionManageAPIKeys issues and uses organization-bound API keys.
	PermissionManageAPIKeys Permission = "api_key.manage"
	// PermissionManageSSO configures the organization's SSO connections and
	// verified domains. It is owner-only: a connection decides which identity
	// provider can sign members in.
	PermissionManageSSO Permission       = "sso.manage"
	ChangeRoleOperation plugin.Operation = "organization.member.role.change"
)

type Plugin

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

func New

func New() *Plugin

func (*Plugin) AcceptInvitation

func (p *Plugin) AcceptInvitation(ctx context.Context, id string, token sigil.Secret) (Tenant, error)

AcceptInvitation requires the authenticated account's current verified email. Consumption and membership insertion commit together. Existing members retain their role; acceptance never promotes a member or downgrades an owner.

func (*Plugin) Active

func (p *Plugin) Active(ctx context.Context) (Tenant, error)

func (*Plugin) Bind

func (p *Plugin) Bind(a *sigil.Auth) error

func (*Plugin) ChangeRole

func (p *Plugin) ChangeRole(ctx context.Context, id, userID string, role Role) (Tenant, error)

ChangeRole changes an existing non-owner to member or admin. Only the live owner can do so; ownership changes must use TransferOwnership. The returned tenant describes the target. Existing sessions observe the role on next use.

func (*Plugin) Create

func (p *Plugin) Create(ctx context.Context, name string) (Tenant, error)

Create atomically creates an organization and the caller's owner membership.

func (*Plugin) Definition

func (p *Plugin) Definition() plugin.Definition

func (*Plugin) Get

func (p *Plugin) Get(ctx context.Context, id string) (Tenant, error)

func (*Plugin) Invite

func (p *Plugin) Invite(ctx context.Context, id, email string) (IssuedInvitation, error)

Invite issues a member invitation bound to a canonical email and tenant. Reissuing for the same tenant/email invalidates every earlier invitation.

func (*Plugin) RemoveMember

func (p *Plugin) RemoveMember(ctx context.Context, id, userID string) error

RemoveMember permits owners to remove non-owners, admins to remove regular members, and any non-owner to leave. The sole owner must transfer first. Cascades clear every active selection.

func (*Plugin) Rename

func (p *Plugin) Rename(ctx context.Context, id, name string) (Tenant, error)

Rename requires recent authentication and owner or admin permission.

func (*Plugin) RevokeInvitation

func (p *Plugin) RevokeInvitation(ctx context.Context, id, invitationID string) error

func (*Plugin) SetActive

func (p *Plugin) SetActive(ctx context.Context, id string) (Tenant, error)

func (*Plugin) TransferOwnership

func (p *Plugin) TransferOwnership(ctx context.Context, id, userID string) (Tenant, error)

TransferOwnership atomically promotes an existing member and demotes the caller. Exactly one owner exists at commit. Outstanding invitations are revoked so authority granted by the former owner does not survive transfer.

func (*Plugin) WithActive

func (p *Plugin) WithActive(ctx context.Context, op plugin.Operation, fn func(storage.Tx, Tenant) error) error

WithActive resolves the session selection and rechecks membership on every call. A missing selection (including removal) fails closed with forbidden.

func (*Plugin) WithPermission

func (p *Plugin) WithPermission(ctx context.Context, id string, permission Permission, op plugin.Operation, fn func(storage.Tx, Tenant) error) error

WithPermission checks a live role and session and holds tenant locks through the callback commit. Administrative permissions require recent sensitive assurance. The host must still bind application resources to this tenant.

func (*Plugin) WithTenant

func (p *Plugin) WithTenant(ctx context.Context, id string, op plugin.Operation, fn func(storage.Tx, Tenant) error) error

WithTenant authorizes live membership and runs trusted application work in the same transaction. Always scope resource queries to tenant.Organization.ID. Never retain tx or use this snapshot as a later authorization decision.

type Role

type Role string

Role is a closed organization role. Unknown roles grant no permissions.

const (
	RoleOwner  Role = "owner"
	RoleAdmin  Role = "admin"
	RoleMember Role = "member"
)

func (Role) Allows

func (r Role) Allows(p Permission) bool

Allows evaluates the role matrix only. It does not authenticate a caller or establish freshness. Use WithPermission for an atomic authorization decision. Removal additionally restricts the target: admins may remove only members.

type Tenant

type Tenant struct {
	Organization Organization `json:"organization"`
	Membership   Membership   `json:"membership"`
}

func LiveMembership

func LiveMembership(tx storage.Tx, id, userID string) (Tenant, error)

LiveMembership reads userID's live membership inside a trusted transaction that already holds that user's core lock, for plugins that bind their own credentials to a tenant. It holds share locks on the organization and membership through commit, so concurrent removal or role changes wait. A missing organization or membership is sigil.ErrForbidden.

func ProvisionMember

func ProvisionMember(tx storage.Tx, id, userID string) (Tenant, error)

ProvisionMember gives userID a member role in organization id unless it already has a membership, whose role is then kept, inside a trusted transaction that already holds that user's core lock. It is for plugins that admit members on the organization's behalf, such as SSO just-in-time membership; it never promotes, and it locks the organization like other lifecycle decisions. A missing organization is sigil.ErrForbidden.

Jump to

Keyboard shortcuts

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