Documentation
¶
Overview ¶
Package organizations provides performance acceleration for organization and membership lookups using GoModularAuth's core cache adapter.
Package organizations provides multi-tenancy and organization management capabilities (reserved module).
Index ¶
- Constants
- Variables
- func ConstantTimeCompare(expectedHash, actualHash string) bool
- func GenerateID(prefix string) string
- func GenerateToken() (string, error)
- func HashToken(rawToken string) string
- func OrganizationFromContext(ctx context.Context) (string, bool)
- func RegisterSchema(s *schema.Schema) error
- func WithOrganizationContext(ctx context.Context, orgID string) context.Context
- type AddMemberInput
- type Cache
- func (c *Cache) Available() bool
- func (c *Cache) DeleteMembership(ctx context.Context, orgID, userID string) error
- func (c *Cache) DeleteOrganization(ctx context.Context, id, slug string) error
- func (c *Cache) GetMembership(ctx context.Context, orgID, userID string) (*Membership, error)
- func (c *Cache) GetOrganizationByID(ctx context.Context, id string) (*OrganizationRecord, error)
- func (c *Cache) GetOrganizationBySlug(ctx context.Context, slug string) (*OrganizationRecord, error)
- func (c *Cache) SetMembership(ctx context.Context, m *Membership, ttl time.Duration) error
- func (c *Cache) SetOrganization(ctx context.Context, org *OrganizationRecord, ttl time.Duration) error
- type Capability
- type Config
- type CreateInvitationInput
- type CreateOrganizationInput
- type CreateTeamInput
- type Hooks
- type Invitation
- type InvitationAcceptedPayload
- type InvitationCreatedPayload
- type InvitationRevokedPayload
- type MemberAddedPayload
- type MemberRemovedPayload
- type MemberUpdatedPayload
- type Membership
- type MembershipStatus
- type Module
- type Option
- type Organization
- type OrganizationCreatedPayload
- type OrganizationDeletedPayload
- type OrganizationRecord
- type OrganizationUpdatedPayload
- type Organizations
- type OwnershipTransferredPayload
- type Role
- type ScopedPrincipal
- type Team
- type TeamCreatedPayload
- type TeamDeletedPayload
- type TeamMemberPayload
- type TeamMembership
- type TeamUpdatedPayload
- type UpdateOrganizationInput
- type UpdateTeamInput
Constants ¶
const ( DefaultCacheTTL = 5 * time.Minute DefaultInvitationTTL = 7 * 24 * time.Hour // 7 days )
Default configurations.
const ( ModelOrganizations = "organizations" ModelOrganizationMemberships = "organization_memberships" ModelOrganizationTeams = "organization_teams" ModelOrganizationTeamMembers = "organization_team_members" ModelOrganizationInvitations = "organization_invitations" )
const ( EventOrganizationCreated auth.EventName = "organizations.created" EventOrganizationUpdated auth.EventName = "organizations.updated" EventOrganizationDeleted auth.EventName = "organizations.deleted" EventOwnershipTransferred auth.EventName = "organizations.ownership_transferred" EventMemberAdded auth.EventName = "organizations.member_added" EventMemberUpdated auth.EventName = "organizations.member_updated" EventMemberRemoved auth.EventName = "organizations.member_removed" EventTeamCreated auth.EventName = "organizations.team_created" EventTeamUpdated auth.EventName = "organizations.team_updated" EventTeamDeleted auth.EventName = "organizations.team_deleted" EventTeamMemberAdded auth.EventName = "organizations.team_member_added" EventTeamMemberRemoved auth.EventName = "organizations.team_member_removed" EventInvitationCreated auth.EventName = "organizations.invitation_created" EventInvitationAccepted auth.EventName = "organizations.invitation_accepted" EventInvitationRevoked auth.EventName = "organizations.invitation_revoked" )
Event names emitted by the organizations plugin.
const PluginID = "organizations"
PluginID identifies this plugin in the GoModularAuth runtime.
const (
// SubNamespace is the plugin sub-namespace within GoModularAuth cache keys.
SubNamespace = "organizations"
)
Variables ¶
var ( // ErrOrganizationNotFound is returned when an organization does not exist. ErrOrganizationNotFound = errors.New("organizations: organization not found") // ErrOrganizationAlreadyExists is returned when an organization with the same slug already exists. ErrOrganizationAlreadyExists = errors.New("organizations: organization already exists") // ErrMemberNotFound is returned when a user is not a member of the organization. ErrMemberNotFound = errors.New("organizations: member not found") // ErrMemberAlreadyExists is returned when a user is already a member of the organization. ErrMemberAlreadyExists = errors.New("organizations: member already exists") // ErrCannotRemoveOwner is returned when attempting to remove or demote the organization owner. ErrCannotRemoveOwner = errors.New("organizations: cannot remove or demote organization owner") ErrUnauthorized = errors.New("organizations: unauthorized operation") // ErrCrossOrganizationAccess is returned when attempting an operation across tenant boundaries. ErrCrossOrganizationAccess = errors.New("organizations: cross-organization access forbidden") // ErrTeamNotFound is returned when a team does not exist. ErrTeamNotFound = errors.New("organizations: team not found") // ErrTeamAlreadyExists is returned when a team with the same slug already exists in the organization. ErrTeamAlreadyExists = errors.New("organizations: team already exists") // ErrTeamMemberNotFound is returned when a user is not a member of the team. ErrTeamMemberNotFound = errors.New("organizations: team member not found") // ErrTeamMemberAlreadyExists is returned when a user is already in the team. ErrTeamMemberAlreadyExists = errors.New("organizations: team member already exists") // ErrInvitationNotFound is returned when an invitation does not exist. ErrInvitationNotFound = errors.New("organizations: invitation not found") // ErrInvitationExpired is returned when attempting to accept an expired invitation. ErrInvitationExpired = errors.New("organizations: invitation expired") // ErrInvitationAlreadyAccepted is returned when attempting to accept an already redeemed invitation. ErrInvitationAlreadyAccepted = errors.New("organizations: invitation already accepted") // ErrInvalidInput is returned when input validation fails. ErrInvalidInput = errors.New("organizations: invalid input") // ErrStoreRequired is returned during plugin initialization when no store is provided. ErrStoreRequired = errors.New("organizations: store is required") )
Functions ¶
func ConstantTimeCompare ¶
ConstantTimeCompare verifies whether two token hashes match without timing leakage.
func GenerateID ¶
GenerateID produces a cryptographically random, prefixed unique identifier.
func GenerateToken ¶
GenerateToken generates a cryptographically secure 32-byte random hex token.
func OrganizationFromContext ¶
OrganizationFromContext retrieves the organization ID bound to ctx, if present.
func RegisterSchema ¶
RegisterSchema registers all organizations-related models into the compiled schema.
Types ¶
type AddMemberInput ¶
type AddMemberInput struct {
OrganizationID string `json:"organization_id"`
UserID string `json:"user_id"`
Role Role `json:"role"`
}
AddMemberInput contains parameters for adding a member to an organization.
type Cache ¶
type Cache struct {
// contains filtered or unexported fields
}
Cache wraps the core cache adapter for organization and membership lookups.
func NewCache ¶
NewCache creates a new Cache wrapper. If core is nil, the cache operates in no-op mode.
func (*Cache) DeleteMembership ¶
DeleteMembership invalidates cached membership for an organization member.
func (*Cache) DeleteOrganization ¶
DeleteOrganization invalidates cache entries for an organization ID and slug.
func (*Cache) GetMembership ¶
GetMembership retrieves a membership from cache.
func (*Cache) GetOrganizationByID ¶
GetOrganizationByID retrieves an organization by ID from cache.
func (*Cache) GetOrganizationBySlug ¶
func (c *Cache) GetOrganizationBySlug(ctx context.Context, slug string) (*OrganizationRecord, error)
GetOrganizationBySlug retrieves an organization by slug from cache.
func (*Cache) SetMembership ¶
SetMembership caches a membership record.
func (*Cache) SetOrganization ¶
func (c *Cache) SetOrganization(ctx context.Context, org *OrganizationRecord, ttl time.Duration) error
SetOrganization caches an organization by its ID and slug.
type Capability ¶
type Capability = Organization
Capability is an alias for Organization to support standard capability discovery conventions.
type Config ¶
type Config struct {
// CacheTTL controls how long organizations and memberships are cached.
// Defaults to 5 minutes. If non-positive, caching is disabled.
CacheTTL time.Duration
// DefaultInvitationTTL sets the duration an invitation remains valid.
// Defaults to 7 days.
DefaultInvitationTTL time.Duration
}
Config configures the organizations plugin module.
type CreateInvitationInput ¶
type CreateInvitationInput struct {
OrganizationID string `json:"organization_id"`
Email string `json:"email"`
Role Role `json:"role"`
InviterUserID string `json:"inviter_user_id"`
TTL time.Duration `json:"ttl,omitempty"`
}
CreateInvitationInput contains parameters for inviting a user by email.
type CreateOrganizationInput ¶
type CreateOrganizationInput struct {
Name string `json:"name"`
Slug string `json:"slug"`
OwnerID string `json:"owner_id"`
Metadata map[string]string `json:"metadata,omitempty"`
}
CreateOrganizationInput contains parameters for creating a new organization.
type CreateTeamInput ¶
type CreateTeamInput struct {
OrganizationID string `json:"organization_id"`
Name string `json:"name"`
Slug string `json:"slug"`
Description string `json:"description,omitempty"`
}
CreateTeamInput contains parameters for creating a new team.
type Hooks ¶
type Hooks struct {
// contains filtered or unexported fields
}
Hooks provides custom interceptor hooks for organization workflows.
func (*Hooks) AfterMemberAdd ¶
func (h *Hooks) AfterMemberAdd(fn sdk.HookFunc[*Membership])
AfterMemberAdd registers a hook executed after a member has been added.
func (*Hooks) AfterOrganizationCreate ¶
func (h *Hooks) AfterOrganizationCreate(fn sdk.HookFunc[*OrganizationRecord])
AfterOrganizationCreate registers a hook executed after organization and owner creation commit.
func (*Hooks) BeforeMemberAdd ¶
func (h *Hooks) BeforeMemberAdd(fn sdk.HookFunc[*AddMemberInput])
BeforeMemberAdd registers a hook executed before adding a member to an organization.
func (*Hooks) BeforeOrganizationCreate ¶
func (h *Hooks) BeforeOrganizationCreate(fn sdk.HookFunc[*CreateOrganizationInput])
BeforeOrganizationCreate registers a hook executed prior to organization persistence.
type Invitation ¶
type Invitation struct {
ID string `json:"id"`
OrganizationID string `json:"organization_id"`
Email string `json:"email"`
Role Role `json:"role"`
InviterUserID string `json:"inviter_user_id"`
TokenHash string `json:"token_hash"`
ExpiresAt time.Time `json:"expires_at"`
AcceptedAt *time.Time `json:"accepted_at,omitempty"`
CreatedAt time.Time `json:"created_at"`
}
Invitation represents an invitation sent to an email address to join an organization.
func (*Invitation) Accepted ¶
func (inv *Invitation) Accepted() bool
Accepted reports whether the invitation has already been redeemed.
type InvitationAcceptedPayload ¶
type InvitationAcceptedPayload struct {
OrganizationID string `json:"organization_id"`
InvitationID string `json:"invitation_id"`
UserID string `json:"user_id"`
AcceptedAt time.Time `json:"accepted_at"`
}
InvitationAcceptedPayload describes an invitation redemption event.
type InvitationCreatedPayload ¶
type InvitationCreatedPayload struct {
OrganizationID string `json:"organization_id"`
InvitationID string `json:"invitation_id"`
Email string `json:"email"`
Role Role `json:"role"`
InviterUserID string `json:"inviter_user_id"`
ExpiresAt time.Time `json:"expires_at"`
}
InvitationCreatedPayload describes an invitation creation event.
type InvitationRevokedPayload ¶
type InvitationRevokedPayload struct {
OrganizationID string `json:"organization_id"`
InvitationID string `json:"invitation_id"`
}
InvitationRevokedPayload describes an invitation revocation event.
type MemberAddedPayload ¶
type MemberAddedPayload struct {
OrganizationID string `json:"organization_id"`
UserID string `json:"user_id"`
Role Role `json:"role"`
}
MemberAddedPayload describes a member addition event.
type MemberRemovedPayload ¶
type MemberRemovedPayload struct {
OrganizationID string `json:"organization_id"`
UserID string `json:"user_id"`
}
MemberRemovedPayload describes a member removal event.
type MemberUpdatedPayload ¶
type MemberUpdatedPayload struct {
OrganizationID string `json:"organization_id"`
UserID string `json:"user_id"`
Role Role `json:"role"`
Status MembershipStatus `json:"status"`
}
MemberUpdatedPayload describes a member role or status change event.
type Membership ¶
type Membership struct {
ID string `json:"id"`
OrganizationID string `json:"organization_id"`
UserID string `json:"user_id"`
Role Role `json:"role"`
Status MembershipStatus `json:"status"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
Membership represents the association between a Core User and an Organization.
func (*Membership) Active ¶
func (m *Membership) Active() bool
Active reports whether the membership is active.
type MembershipStatus ¶
type MembershipStatus string
MembershipStatus indicates the lifecycle state of an organization membership.
const ( MembershipActive MembershipStatus = "active" MembershipSuspended MembershipStatus = "suspended" )
type Module ¶
type Module struct {
// contains filtered or unexported fields
}
Module implements auth.PluginModule using plugin-sdk.
type Option ¶
type Option func(*Config)
Option configures a Config.
func WithCacheTTL ¶
WithCacheTTL configures the caching TTL duration for organizations and memberships.
func WithDefaultInvitationTTL ¶
WithDefaultInvitationTTL sets the default validity duration for newly created invitations.
type Organization ¶
type Organization interface {
// CreateOrganization atomically creates a new Organization and adds the owner as the initial active member with RoleOwner.
CreateOrganization(ctx context.Context, in CreateOrganizationInput) (*OrganizationRecord, error)
// GetOrganization retrieves an organization by its unique ID.
GetOrganization(ctx context.Context, orgID string) (*OrganizationRecord, error)
// GetOrganizationBySlug retrieves an organization by its unique URL slug.
GetOrganizationBySlug(ctx context.Context, slug string) (*OrganizationRecord, error)
// UpdateOrganization modifies an existing organization's name or metadata.
UpdateOrganization(ctx context.Context, orgID string, in UpdateOrganizationInput) (*OrganizationRecord, error)
// DeleteOrganization deletes an organization, cascading to members, teams, and invitations.
DeleteOrganization(ctx context.Context, orgID string) error
// ListUserOrganizations retrieves all organizations where the specified user is an active member.
ListUserOrganizations(ctx context.Context, userID string) ([]*OrganizationRecord, error)
// TransferOwnership assigns the organization's ownership to another existing member.
TransferOwnership(ctx context.Context, orgID, newOwnerUserID string) error
// AddMember associates a Core User with the organization with a specific role.
AddMember(ctx context.Context, in AddMemberInput) (*Membership, error)
// GetMember retrieves a membership record for a user in an organization.
GetMember(ctx context.Context, orgID, userID string) (*Membership, error)
// UpdateMemberRole updates the role assigned to a member.
UpdateMemberRole(ctx context.Context, orgID, userID string, role Role) (*Membership, error)
// UpdateMemberStatus updates the membership status (e.g. active, suspended).
UpdateMemberStatus(ctx context.Context, orgID, userID string, status MembershipStatus) (*Membership, error)
// RemoveMember removes a user from an organization. Cannot remove the owner.
RemoveMember(ctx context.Context, orgID, userID string) error
// ListMembers retrieves all members of an organization.
ListMembers(ctx context.Context, orgID string) ([]*Membership, error)
// CreateTeam creates a new team within an organization.
CreateTeam(ctx context.Context, in CreateTeamInput) (*Team, error)
// GetTeam retrieves a team by ID within the target organization.
GetTeam(ctx context.Context, orgID, teamID string) (*Team, error)
// UpdateTeam updates team details within an organization.
UpdateTeam(ctx context.Context, orgID, teamID string, in UpdateTeamInput) (*Team, error)
// DeleteTeam removes a team and its member associations.
DeleteTeam(ctx context.Context, orgID, teamID string) error
// ListTeams retrieves all teams belonging to an organization.
ListTeams(ctx context.Context, orgID string) ([]*Team, error)
// AddTeamMember enrolls an organization member into a team.
AddTeamMember(ctx context.Context, orgID, teamID, userID string) error
// RemoveTeamMember removes a user from a team.
RemoveTeamMember(ctx context.Context, orgID, teamID, userID string) error
// ListTeamMembers retrieves all user IDs belonging to a team.
ListTeamMembers(ctx context.Context, orgID, teamID string) ([]string, error)
// CreateInvitation creates an invitation for an email address and returns the invitation and plaintext redemption token.
CreateInvitation(ctx context.Context, in CreateInvitationInput) (*Invitation, string, error)
// GetInvitation retrieves an invitation by ID within an organization.
GetInvitation(ctx context.Context, orgID, invitationID string) (*Invitation, error)
// ListInvitations lists all pending invitations for an organization.
ListInvitations(ctx context.Context, orgID string) ([]*Invitation, error)
// AcceptInvitation redeems an invitation token for a user, adding them as a member.
AcceptInvitation(ctx context.Context, rawToken, userID string) (*Membership, error)
// RevokeInvitation revokes an invitation before it is accepted.
RevokeInvitation(ctx context.Context, orgID, invitationID string) error
// Authorize checks whether the context's authenticated Core Principal has active membership with at least minRole in orgID.
Authorize(ctx context.Context, orgID string, minRole Role) (*Membership, error)
}
Organization is the strongly typed capability provided by the organizations module. Applications access it via auth.Get[plugins.Organization](a) or auth.Get[organizations.Organization](a).
type OrganizationCreatedPayload ¶
type OrganizationCreatedPayload struct {
OrganizationID string `json:"organization_id"`
Slug string `json:"slug"`
OwnerID string `json:"owner_id"`
CreatedAt time.Time `json:"created_at"`
}
OrganizationCreatedPayload describes an organization creation event.
type OrganizationDeletedPayload ¶
type OrganizationDeletedPayload struct {
OrganizationID string `json:"organization_id"`
DeletedAt time.Time `json:"deleted_at"`
}
OrganizationDeletedPayload describes an organization deletion event.
type OrganizationRecord ¶
type OrganizationRecord struct {
ID string `json:"id"`
Name string `json:"name"`
Slug string `json:"slug"`
OwnerID string `json:"owner_id"`
Metadata map[string]string `json:"metadata,omitempty"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
OrganizationRecord represents an isolated multi-tenant tenant boundary.
type OrganizationUpdatedPayload ¶
type OrganizationUpdatedPayload struct {
OrganizationID string `json:"organization_id"`
UpdatedAt time.Time `json:"updated_at"`
}
OrganizationUpdatedPayload describes an organization modification event.
type Organizations ¶
type Organizations = Organization
Organizations is an alias for Organization to support plural capability naming conventions.
type OwnershipTransferredPayload ¶
type OwnershipTransferredPayload struct {
OrganizationID string `json:"organization_id"`
OldOwnerID string `json:"old_owner_id"`
NewOwnerID string `json:"new_owner_id"`
}
OwnershipTransferredPayload describes an ownership change event.
type Role ¶
type Role string
Role represents a member's role within an organization.
type ScopedPrincipal ¶
type ScopedPrincipal struct {
Principal auth.Principal
OrganizationID string
Membership *Membership
}
ScopedPrincipal binds an authenticated Core Principal with an Organization scope.
type Team ¶
type Team struct {
ID string `json:"id"`
OrganizationID string `json:"organization_id"`
Name string `json:"name"`
Slug string `json:"slug"`
Description string `json:"description,omitempty"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
Team represents a logical group of members within an organization.
type TeamCreatedPayload ¶
type TeamCreatedPayload struct {
OrganizationID string `json:"organization_id"`
TeamID string `json:"team_id"`
Slug string `json:"slug"`
}
TeamCreatedPayload describes a team creation event.
type TeamDeletedPayload ¶
type TeamDeletedPayload struct {
OrganizationID string `json:"organization_id"`
TeamID string `json:"team_id"`
}
TeamDeletedPayload describes a team deletion event.
type TeamMemberPayload ¶
type TeamMemberPayload struct {
OrganizationID string `json:"organization_id"`
TeamID string `json:"team_id"`
UserID string `json:"user_id"`
}
TeamMemberPayload describes adding or removing a member from a team.
type TeamMembership ¶
type TeamMembership struct {
ID string `json:"id"`
TeamID string `json:"team_id"`
UserID string `json:"user_id"`
CreatedAt time.Time `json:"created_at"`
}
TeamMembership represents a user's enrollment within a team.
type TeamUpdatedPayload ¶
type TeamUpdatedPayload struct {
OrganizationID string `json:"organization_id"`
TeamID string `json:"team_id"`
}
TeamUpdatedPayload describes a team update event.
type UpdateOrganizationInput ¶
type UpdateOrganizationInput struct {
Name *string `json:"name,omitempty"`
Metadata map[string]string `json:"metadata,omitempty"`
}
UpdateOrganizationInput contains parameters for updating an organization.
type UpdateTeamInput ¶
type UpdateTeamInput struct {
Name *string `json:"name,omitempty"`
Description *string `json:"description,omitempty"`
}
UpdateTeamInput contains parameters for updating a team.
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
Package migrations contains SQL schema migrations for the organizations plugin.
|
Package migrations contains SQL schema migrations for the organizations plugin. |
|
Package plugins exposes capability aliases for GoModularAuth plugins.
|
Package plugins exposes capability aliases for GoModularAuth plugins. |