Documentation
¶
Overview ¶
Package identity owns identity-domain values and workflows. Persistence and authentication ceremonies are composed through separate adapters. Identifiers identify records or attempts; possession does not confer authority.
Index ¶
- Variables
- func AccountLinkIntentDigest(c AccountLinkChange) ([32]byte, error)
- func BuildAccountLinkProofPayload(s AccountLinkProofSpec) (capability.Payload, error)
- func BuildIdentifierProofPayload(s IdentifierProofSpec) (capability.Payload, error)
- func BuildPrivacyExportProofPayload(s PrivacyExportProofSpec) (capability.Payload, error)
- func CheckCredentialAuthority(current CredentialAuthorityRecord, expected CredentialRef, ...) error
- func CheckPasswordRecoveryAuthority(current CredentialAuthorityRecord, expected CredentialRef, ...) error
- func ComparePreAuthTransactionID(left, right PreAuthTransactionID) (int, error)
- func CompareSubjectID(left, right SubjectID) (int, error)
- func FormatPreAuthTransactionID(id PreAuthTransactionID) string
- func FormatSubjectID(id SubjectID) string
- func IdentifierChangeConsumers() []string
- func IdentifierIntentDigest(c IdentifierChange) ([32]byte, error)
- func IdentifierRemovalConsumers() []string
- func PrivacyExportContributorsV1() []string
- func PrivacyExportIntentDigest(c PrivacyExportRequestCommand) ([32]byte, error)
- type Account
- type AccountAccessSnapshot
- type AccountID
- type AccountLinkChange
- type AccountLinkCommand
- type AccountLinkConfig
- type AccountLinkMode
- type AccountLinkMutation
- type AccountLinkProofSpec
- type AccountLinkQuery
- type AccountLinkReceipt
- type AccountLinkRecoveryRequest
- type AccountLinkRepository
- type AccountLinkRequest
- type AccountLinkResult
- type AccountLinkService
- type AccountLinkState
- type AccountListRequest
- type AccountListResult
- type AccountQuery
- type AccountRepository
- type AccountService
- type AccountSnapshot
- type AccountUnlinkChange
- type AccountUnlinkCommand
- type AccountUnlinkConfig
- type AccountUnlinkMutation
- type AccountUnlinkPlan
- type AccountUnlinkQuery
- type AccountUnlinkReceipt
- type AccountUnlinkRecoveryRequest
- type AccountUnlinkRepository
- type AccountUnlinkRequest
- type AccountUnlinkResult
- type AccountUnlinkService
- type AccountUnlinkState
- type ActorID
- type AfterHookInput
- type AssessRiskFunc
- type AttemptedCommitOutcome
- type AttributeKind
- type AttributePrepareRequest
- type AttributeProcessor
- type AttributeProcessorConfig
- type AttributeScalar
- type AttributeSchema
- type AttributeUpdate
- type AttributeValue
- type BeforeHookDecision
- type BeforeHookInput
- type BeforeHookResult
- type CancelledError
- type CanonicalUserIDValidator
- type Cardinality
- type CascadeID
- type ClaimsPolicyDecision
- type ClaimsPolicyInput
- type Command
- func BindPhonePasswordResetPreAuth(original Command, cookie auth.BearerCredential) (Command, error)
- func NewAccountLinkCommand(s AccountLinkCommand) (Command, error)
- func NewAccountUnlinkCommand(s AccountUnlinkCommand) (Command, error)
- func NewFeatureCommand(spec FeatureCommandSpec) (Command, error)
- func NewFeatureOneTimeCodeCommand(spec FeatureCommandSpec, code authentication.OneTimeCode) (Command, error)
- func NewFeatureOneTimeCodePreAuthCommand(spec FeatureCommandSpec, code authentication.OneTimeCode, ...) (Command, error)
- func NewFeatureOneTimeCodeSessionCommand(spec FeatureCommandSpec, code authentication.OneTimeCode, ...) (Command, error)
- func NewFeaturePasswordChangeCommand(spec FeatureCommandSpec, encodedHash string, ...) (Command, error)
- func NewFeaturePasswordHashCommand(spec FeatureCommandSpec, encodedHash string) (Command, error)
- func NewFeaturePasswordResetCommand(spec FeatureCommandSpec, encodedHash string, proof capability.Proof) (Command, error)
- func NewFeaturePasswordResetInputCommand(spec FeatureCommandSpec, password primitive.Secret, proof capability.Proof) (Command, error)
- func NewFeaturePasswordSigninCommand(spec FeatureCommandSpec, password primitive.Secret, ...) (Command, error)
- func NewFeaturePasswordSignupCommand(spec FeatureCommandSpec, encodedHash string, ...) (Command, error)
- func NewFeaturePasswordSignupInputCommand(spec FeatureCommandSpec, password primitive.Secret, ...) (Command, error)
- func NewFeaturePhonePasswordResetCommand(spec FeatureCommandSpec, encodedHash string, proof capability.Proof, ...) (Command, error)
- func NewFeaturePhonePasswordResetInputCommand(spec FeatureCommandSpec, password primitive.Secret, proof capability.Proof, ...) (Command, error)
- func NewFeaturePreAuthCommand(spec FeatureCommandSpec, cookie authentication.BearerCredential) (Command, error)
- func NewFeatureRecoveryCodePreAuthCommand(spec FeatureCommandSpec, code authentication.RecoveryCode, ...) (Command, error)
- func NewFeatureSessionCommand(spec FeatureCommandSpec, token authentication.BearerCredential) (Command, error)
- func NewIdentifierCommand(c IdentifierCommand) (Command, error)
- func NewPrivacyExportRequestCommand(c PrivacyExportRequestCommand) (Command, error)
- func NewProfileUpdateCommand(spec ProfileUpdateCommand) (Command, error)
- func NewUserCreationCommand(spec CreateUserCommand) (Command, error)
- func NewUserStatusCommand(spec UserStatusCommand) (Command, error)
- func NewUserUpdateCommand(spec UpdateUserCommand) (Command, error)
- func (c Command) ChangeIdentifier() (IdentifierCommand, bool)
- func (c Command) CreateUser() (CreateUserCommand, bool)
- func (c Command) Feature() (FeatureCommandSpec, bool)
- func (Command) Format(state fmt.State, verb rune)
- func (c Command) IdentifierProof() (capability.Proof, bool)
- func (c Command) LinkAccount() (AccountLinkCommand, bool)
- func (Command) MarshalJSON() ([]byte, error)
- func (c Command) OneTimeCode() (authentication.OneTimeCode, bool)
- func (c Command) PasswordChangeCustody() (string, authentication.BearerCredential, authentication.ReauthenticationProof, ...)
- func (c Command) PasswordChangeFeature() (FeatureCommandSpec, bool)
- func (c Command) PasswordHash() (string, bool)
- func (c Command) PasswordHashFeature() (FeatureCommandSpec, bool)
- func (c Command) PasswordResetCustody() (string, capability.Proof, bool)
- func (c Command) PasswordResetFeature() (FeatureCommandSpec, bool)
- func (c Command) PasswordResetInputCustody() (primitive.Secret, capability.Proof, bool)
- func (c Command) PasswordResetInputFeature() (FeatureCommandSpec, bool)
- func (c Command) PasswordSigninCustody() (primitive.Secret, authentication.BearerCredential, bool)
- func (c Command) PasswordSigninFeature() (FeatureCommandSpec, bool)
- func (c Command) PasswordSignupCustody() (string, authentication.BearerCredential, bool)
- func (c Command) PasswordSignupFeature() (FeatureCommandSpec, bool)
- func (c Command) PasswordSignupInputCustody() (primitive.Secret, authentication.BearerCredential, bool)
- func (c Command) PasswordSignupInputFeature() (FeatureCommandSpec, bool)
- func (c Command) PhonePasswordResetCustody() (string, capability.Proof, auth.OneTimeCode, auth.OneTimeCode, bool)
- func (c Command) PhonePasswordResetFeature() (FeatureCommandSpec, bool)
- func (c Command) PhonePasswordResetInputCustody() (primitive.Secret, capability.Proof, auth.OneTimeCode, auth.OneTimeCode, bool)
- func (c Command) PhonePasswordResetInputFeature() (FeatureCommandSpec, bool)
- func (c Command) PhonePasswordResetPreAuthCookie() (auth.BearerCredential, bool)
- func (c Command) PreAuthCookie() (authentication.BearerCredential, bool)
- func (c Command) PrivacyExportProof() (capability.Proof, bool)
- func (c Command) RecoveryCode() (authentication.RecoveryCode, bool)
- func (c Command) RequestPrivacyExport() (PrivacyExportRequestCommand, bool)
- func (c Command) SessionToken() (authentication.BearerCredential, bool)
- func (c Command) UnlinkAccount() (AccountUnlinkCommand, bool)
- func (c Command) UpdateProfile() (ProfileUpdateCommand, bool)
- func (c Command) UpdateUser() (UpdateUserCommand, bool)
- func (c Command) UserStatus() (UserStatusCommand, bool)
- type CommandBinding
- type CommandID
- type CommandResult
- type CommitOutcome
- type ConflictError
- type CreateUserCommand
- type CredentialAuthorityQuery
- type CredentialAuthorityRecord
- type CredentialAuthorityRepository
- type CredentialID
- type CredentialKind
- type CredentialRef
- type Cursor
- type DeadlineExceededError
- type DecideRetentionFunc
- type DeliverySecurityEventInput
- type DeliverySecurityTransition
- type FeatureCommandSpec
- type FeatureField
- type FeatureKind
- type FeatureOperation
- type FeatureReceipt
- type FeatureRecordRequirement
- type FeatureSubjectRequirement
- type FeatureValue
- type FieldAuthorization
- type FieldName
- type FieldPermission
- type FieldPolicy
- type FinalAccessError
- type ForbiddenError
- type GetUserQuery
- type Hook
- type HookEnrichment
- type HookField
- type HookFieldRegistration
- type HookObservation
- type HookRunner
- type HookRunnerConfig
- type IdempotencyKey
- type Identifier
- type IdentifierAccessPlan
- type IdentifierAccessSnapshot
- type IdentifierAction
- type IdentifierChange
- type IdentifierChangeRequest
- type IdentifierCommand
- type IdentifierConfig
- type IdentifierID
- type IdentifierKind
- type IdentifierLoginMethod
- type IdentifierMutation
- type IdentifierPrimarySelection
- type IdentifierProjection
- func (p IdentifierProjection) Bindings() (IdentifierProjectionBindings, error)
- func (IdentifierProjection) Format(s fmt.State, _ rune)
- func (IdentifierProjection) LogValue() slog.Value
- func (IdentifierProjection) MarshalJSON() ([]byte, error)
- func (IdentifierProjection) MarshalText() ([]byte, error)
- func (p IdentifierProjection) Values() (canonical, display string, present bool)
- type IdentifierProjectionBindings
- type IdentifierProjectionSpec
- type IdentifierProofSpec
- type IdentifierQuery
- type IdentifierReceipt
- type IdentifierRecoveryRequest
- type IdentifierRepository
- type IdentifierResult
- type IdentifierService
- type IdentifierState
- type IdentifierValueVisibility
- type IdentitySecurityEventV1
- func (b *IdentitySecurityEventV1) Build(ctx context.Context, input SecurityEventInput) (audit.Record, error)
- func (b *IdentitySecurityEventV1) BuildDelivery(ctx context.Context, i DeliverySecurityEventInput) (audit.Record, error)
- func (b *IdentitySecurityEventV1) BuildRiskDecision(ctx context.Context, i RiskSecurityEventInput) (audit.Record, error)
- type InProgressError
- type InvalidInputError
- type LifecycleCascadeAdmission
- type LifecycleCascadeKind
- type ListUsersQuery
- type LoginMethod
- type MapClaimsFunc
- type NormalizationPolicy
- type NormalizeAttributeFunc
- type NotCommittedError
- type OperationContext
- type PolicyEvaluator
- func (e *PolicyEvaluator) AssessRisk(ctx context.Context, in RiskPolicyInput) (RiskPolicyDecision, error)
- func (e *PolicyEvaluator) DecideRetention(ctx context.Context, in RetentionPolicyInput) (RetentionPolicyDecision, error)
- func (e *PolicyEvaluator) MapClaims(ctx context.Context, in ClaimsPolicyInput) (ClaimsPolicyDecision, error)
- func (e *PolicyEvaluator) Redact(ctx context.Context, in RedactionPolicyInput) (RedactionPolicyDecision, error)
- type PolicyEvaluatorConfig
- type PolicyReason
- type PolicySet
- type PreAuthTransactionID
- type PrivacyExportCheckpointV1
- type PrivacyExportConfig
- type PrivacyExportContributorBindingV1
- type PrivacyExportContributorCutV1
- type PrivacyExportEvidenceKey
- type PrivacyExportFragmentClassification
- type PrivacyExportFragmentV1
- type PrivacyExportJobID
- type PrivacyExportProjectionSpecV1
- type PrivacyExportProjectionV1
- type PrivacyExportProofSpec
- type PrivacyExportRecoveryRequest
- type PrivacyExportRequest
- type PrivacyExportRequestCommand
- type PrivacyExportRequestReceipt
- type PrivacyExportResult
- type PrivacyExportService
- func (PrivacyExportService) Format(s fmt.State, verb rune)
- func (PrivacyExportService) MarshalJSON() ([]byte, error)
- func (s *PrivacyExportService) Recover(ctx context.Context, r PrivacyExportRecoveryRequest) (out PrivacyExportResult, err error)
- func (s *PrivacyExportService) Request(ctx context.Context, r PrivacyExportRequest) (out PrivacyExportResult, err error)
- type PrivacyExportSnapshotRecordV1
- type PrivacyExportSnapshotSpecV1
- type PrivacyExportSnapshotV1
- func (s PrivacyExportSnapshotV1) Contributor(id string) (PrivacyExportContributorBindingV1, bool)
- func (PrivacyExportSnapshotV1) Format(s fmt.State, _ rune)
- func (s PrivacyExportSnapshotV1) Record() PrivacyExportSnapshotRecordV1
- func (s PrivacyExportSnapshotV1) Valid() bool
- func (s PrivacyExportSnapshotV1) ValidateFragment(f PrivacyExportFragmentV1, canonical []byte, maximumBytes uint64) error
- type PrivacyExportStatus
- type ProfileConfig
- type ProfileGetRequest
- type ProfileGetResult
- type ProfileQuery
- type ProfileRecord
- type ProfileRecoveryRequest
- type ProfileRepository
- type ProfileService
- func (s *ProfileService) ProfileGet(ctx context.Context, req ProfileGetRequest) (out ProfileGetResult, err error)
- func (s *ProfileService) ProfileUpdate(ctx context.Context, req ProfileUpdateRequest) (out ProfileUpdateResult, err error)
- func (s *ProfileService) RecoverProfileUpdate(ctx context.Context, req ProfileRecoveryRequest) (out ProfileUpdateResult, err error)
- type ProfileUpdateCommand
- type ProfileUpdateRequest
- type ProfileUpdateResult
- type ProviderRevocationOutcome
- type RecoveryQuery
- type RedactFunc
- type RedactionPolicyDecision
- type RedactionPolicyInput
- type RedactionResource
- type RequestIntent
- type RetentionAction
- type RetentionDisposition
- type RetentionPolicyDecision
- type RetentionPolicyInput
- type RetentionResource
- type RevocationOutcome
- type RevocationOwnerReceipt
- type RevocationStatus
- type RiskAction
- type RiskLevel
- type RiskPolicyDecision
- type RiskPolicyInput
- type RiskSecurityDecision
- type RiskSecurityEventInput
- type RiskSignal
- type SecurityAction
- type SecurityEventInput
- type SecurityProvider
- type SecurityProviderKind
- type SecurityProviderProfile
- type SecurityProviderResult
- type SecurityReason
- type SecuritySubject
- type Sensitivity
- type Status
- type StatusPolicy
- type StatusTransition
- type SubjectID
- type TenantID
- type TypedClaim
- type UnauthenticatedError
- type UnavailableError
- type UnitOfWork
- type UnknownCommitError
- type UpdateUserCommand
- type User
- type UserCreateRecoveryRequest
- type UserCreateRequest
- type UserCreateResult
- type UserCreationConfig
- type UserCreationService
- type UserDirectoryRepository
- type UserGetRequest
- type UserGetResult
- type UserID
- type UserListConfig
- type UserListFilters
- type UserListRepository
- type UserListRequest
- type UserListResult
- type UserPage
- type UserProfile
- type UserQueryConfig
- type UserQueryRepository
- type UserQueryService
- type UserStatusCommand
- type UserStatusConfig
- type UserStatusQuery
- type UserStatusRecord
- type UserStatusRecoveryRequest
- type UserStatusRepository
- type UserStatusRequest
- type UserStatusResult
- type UserStatusService
- func (s *UserStatusService) AdminUserBan(ctx context.Context, req UserStatusRequest) (UserStatusResult, error)
- func (s *UserStatusService) AdminUserUnban(ctx context.Context, req UserStatusRequest) (UserStatusResult, error)
- func (s *UserStatusService) RecoverUserStatus(ctx context.Context, req UserStatusRecoveryRequest) (result UserStatusResult, err error)
- func (s *UserStatusService) UserRestore(ctx context.Context, req UserStatusRequest) (UserStatusResult, error)
- func (s *UserStatusService) UserSuspend(ctx context.Context, req UserStatusRequest) (UserStatusResult, error)
- type UserUpdateAdminRecoveryRequest
- type UserUpdateAdminRequest
- type UserUpdateAdminResult
- type UserUpdateAdminService
- type ValidateAttributeFunc
- type Verification
- type VerificationState
Examples ¶
- ApplyAccountLink
- ApplyAccountUnlink
- ApplyIdentifierChange
- AttributeSchema.Validate
- CheckAccountUnlink
- CommandBinding.ValidateFor
- FeatureReceipt
- IdentifierIntentDigest
- NewCursor
- NewFeatureCommand
- NewIdempotencyKey
- NewIdentifierProjection
- NewProfileUpdateCommand
- NewRequestIntent
- NewUserCreationCommand
- NewUserStatusCommand
- NewUserUpdateCommand
- ParsePreAuthTransactionID
- ParseSubjectID
- PolicyEvaluator.AssessRisk
- StatusPolicy.CheckTransition
- User.Validate
Constants ¶
This section is empty.
Variables ¶
var ( // ErrInvalidCommandID identifies noncanonical command IDs without input. ErrInvalidCommandID = errors.New("identity: invalid command ID") // ErrCommandIDEntropy identifies generation failure without provider details. ErrCommandIDEntropy = errors.New("identity: command ID entropy unavailable") )
var ( // ErrInvalidSubjectID identifies malformed, noncanonical or zero subject IDs. // It never contains the rejected input. ErrInvalidSubjectID = errors.New("identity: invalid subject ID") // ErrSubjectIDEntropy identifies unavailable, incomplete or all-zero entropy. // It never includes entropy bytes or provider error details. ErrSubjectIDEntropy = errors.New("identity: subject ID entropy unavailable") // ErrInvalidPreAuthTransactionID identifies invalid attempt IDs without input. ErrInvalidPreAuthTransactionID = errors.New("identity: invalid pre-auth transaction ID") // ErrPreAuthTransactionIDEntropy identifies invalid entropy without details. ErrPreAuthTransactionIDEntropy = errors.New("identity: pre-auth transaction ID entropy unavailable") )
var ( // ErrInvalidPrivacyExportSnapshot redacts malformed or unauthenticated bindings. ErrInvalidPrivacyExportSnapshot = errors.New("identity: invalid privacy export snapshot") // ErrInvalidPrivacyExportFragment redacts mismatched fragment metadata/content. ErrInvalidPrivacyExportFragment = errors.New("identity: invalid privacy export fragment") // ErrPrivacyExportJobIDEntropy reports unavailable export ID entropy. ErrPrivacyExportJobIDEntropy = errors.New("identity: privacy export ID entropy unavailable") )
var ErrCascadeIDEntropy = errors.New("identity: cascade ID entropy unavailable")
ErrCascadeIDEntropy reports cascade generation failure without provider data.
var ErrCredentialAuthority = errors.New("identity: credential authority denied")
ErrCredentialAuthority denies incomplete, stale, inactive or mismatched credential eligibility without identifying the failing field or credential.
var ErrInvalidSecurityEvent = errors.New("identity: invalid security event")
ErrInvalidSecurityEvent rejects unsafe or unsupported profile fields without disclosing input. Construction never proves audit delivery or authorization.
var ErrUserAbsent = errors.New("identity: user absent")
ErrUserAbsent is returned by a repository for enumeration-safe absence. The query service exposes the same ForbiddenError as a denied projection.
Functions ¶
func AccountLinkIntentDigest ¶
func AccountLinkIntentDigest(c AccountLinkChange) ([32]byte, error)
AccountLinkIntentDigest is SHA-256 over the domain identity-account-link-v1 followed by 23 length-prefixed UTF-8 fields in the order implemented below. It is an unkeyed signed-intent binding, NOT authority, a bearer, password hash or reuse tombstone. Exact mode, metadata, fences, credential and identifier choices are bound. Canonical provider policy must run before signing. No secrets are retained; invalid inputs return a zero digest and redacted error.
func BuildAccountLinkProofPayload ¶
func BuildAccountLinkProofPayload(s AccountLinkProofSpec) (capability.Payload, error)
BuildAccountLinkProofPayload owns the canonical eight-caveat issuance shape so feature packages need not reconstruct its binding protocol. It performs no signing, authorization, provider verification or clock read. Only a configured trusted capability signer may issue it after actual proof and policy checks. Time is second-precision UTC, expiry exclusive and no more than five minutes after issuance. The returned payload/map is caller-owned; never log it or confuse a constructed payload with a signed grant.
func BuildIdentifierProofPayload ¶
func BuildIdentifierProofPayload(s IdentifierProofSpec) (capability.Payload, error)
BuildIdentifierProofPayload owns the canonical six-caveat issuance shape. No signing, clock, I/O or proof consumption occurs. Instants have whole-second precision, UTC persisted representation, exclusive expiry and ≤5m lifetime. The returned payload is caller-owned sensitive intent; never log it.
func BuildPrivacyExportProofPayload ¶
func BuildPrivacyExportProofPayload(s PrivacyExportProofSpec) (capability.Payload, error)
BuildPrivacyExportProofPayload prepares one-use, exact-intent issuance after trusted composition has verified the human/session and policy. Instants must have whole-second precision and an exclusive expiry at most five minutes later. No clock, signing, authorization, I/O or consumption occurs here.
func CheckCredentialAuthority ¶
func CheckCredentialAuthority(current CredentialAuthorityRecord, expected CredentialRef, expectedAuthorityVersion uint64, now time.Time) error
CheckCredentialAuthority checks one expected credential against the current primary projection and the original user-wide credential epoch. Exact ID, tenant, user, kind, owner and record version must match. Blocked users and disabled/expired references deny even when both versions match. Ordinary user aggregate changes do not invalidate otherwise equal credential authority. Positive uint64 counters, including MaxUint64, compare without narrowing.
now is the caller's one trusted decision-clock sample. This pure check performs no lookup, mutation, clock sampling, proof validation/consumption, issuance or refresh. Success cannot replace current global/tenant/user/identifier/factor/ provider checks, verified original proof provenance or atomic finalization.
func CheckPasswordRecoveryAuthority ¶
func CheckPasswordRecoveryAuthority(current CredentialAuthorityRecord, expected CredentialRef, expectedAuthorityVersion uint64, expectedEnabled bool, now time.Time) error
CheckPasswordRecoveryAuthority checks the exact enabled or disabled password predecessor for recovery, never authentication. It preserves all current tenant/user/status/reference/epoch/expiry checks and requires the password owner's reference. expectedEnabled must come from original trusted intent, not client policy or an assumption. Success grants neither reset permission nor a session: verified recovery, current factors/risk and atomic one-use mutation remain mandatory. No IO, renewal, metadata substitution or mutation occurs; CheckCredentialAuthority continues to reject disabled references.
func ComparePreAuthTransactionID ¶
func ComparePreAuthTransactionID(left, right PreAuthTransactionID) (int, error)
ComparePreAuthTransactionID compares decoded bytes, returning -1, 0 or 1. Invalid operands return 0 and ErrInvalidPreAuthTransactionID.
func CompareSubjectID ¶
CompareSubjectID returns -1, 0 or 1 in decoded bytewise order, not encoded ASCII order. Invalid operands return 0 and ErrInvalidSubjectID.
func FormatPreAuthTransactionID ¶
func FormatPreAuthTransactionID(id PreAuthTransactionID) string
FormatPreAuthTransactionID returns the canonical encoding or an empty string for an invalid value. No normalization of attacker-supplied text is attempted.
func FormatSubjectID ¶
FormatSubjectID returns the canonical representation or an empty string for an invalid value, including a forged conversion from a noncanonical string.
func IdentifierChangeConsumers ¶
func IdentifierChangeConsumers() []string
IdentifierChangeConsumers returns the exact version-one change manifest. Its consumers match the removal set in LIFECYCLE_CONSUMERS.md; neither set acknowledges asynchronous completion merely because replacement committed.
func IdentifierIntentDigest ¶
func IdentifierIntentDigest(c IdentifierChange) ([32]byte, error)
IdentifierIntentDigest returns a bounded, deterministic domain-separated signed-intent binding. It is not authority, a password hash or a safe reuse tombstone; do not publish/store it as an unhashed private-value index. The encoding is documented in docs/identifiers.md. No normalization occurs.
Example ¶
package main
import (
"fmt"
identity "github.com/faustbrian/go-identity"
)
func main() {
digest, err := identity.IdentifierIntentDigest(identity.IdentifierChange{
TenantID: "tenant-1", UserID: "user-1", Action: identity.IdentifierAttach,
ID: "b", Kind: identity.IdentifierEmail, CanonicalValue: "two@example.test",
ExpectedUserVersion: 4, ExpectedAuthorityVersion: 2,
})
// A digest binds intent. It is not a proof, bearer or safe tombstone.
fmt.Println(err == nil, len(digest))
}
Output: true 32
func IdentifierRemovalConsumers ¶
func IdentifierRemovalConsumers() []string
IdentifierRemovalConsumers returns the complete ordered version-one semantic consumer set. Missing adapters remain pending, never implicitly not-applicable. The caller owns this new slice; mutation cannot change the retained manifest.
func PrivacyExportContributorsV1 ¶
func PrivacyExportContributorsV1() []string
PrivacyExportContributorsV1 returns the exact immutable manifest's 23 ASCII- ordered semantic owners. Adapters and cache projections are not extra owners.
func PrivacyExportIntentDigest ¶
func PrivacyExportIntentDigest(c PrivacyExportRequestCommand) ([32]byte, error)
PrivacyExportIntentDigest binds every unsigned field to a deterministic domain-separated SHA-256 digest. This is a proof caveat, not authorization, an export snapshot or a receipt. Proof metadata itself is excluded. See docs/privacy-snapshot.md for the closed CBOR profile. Invalid input is redacted.
Types ¶
type Account ¶
type Account struct {
ID AccountID
TenantID TenantID
UserID UserID
Provider string
Issuer string
Subject string
Version uint64
}
Account is identity-owned safe provider-link metadata, not provider tokens or a credential verifier. Its zero value is invalid. TenantID makes partition ownership explicit even when the same user/account ID exists in two tenants. Treat snapshots as immutable. Issuer/Subject may be withheld in public results; only complete authoritative records may be validated or used in commands.
func (Account) Validate ¶
Validate checks the exact owner and bounded canonical metadata. It never authorizes access or rewrites provider subjects/issuers. The current provider issuer profiles are HTTPS and federation URNs without query, fragment or credentials. Provider registration owns protocol-specific canonicalization and must separately establish the trusted exact issuer; no URI is fetched.
type AccountAccessSnapshot ¶
type AccountAccessSnapshot struct {
User User
Accounts []Account
Methods []LoginMethod
}
AccountAccessSnapshot is a bounded consistent primary view of every linked account and login method for one user. It is not an authority proof. The durable owner must re-read it under its locks, including credential/factor owner eligibility, rather than trusting caller-provided counts or this view.
type AccountID ¶
type AccountID string
AccountID is an exact case-sensitive directory ID of at most 128 UTF-8 bytes. It preserves canonical imported IDs, including ULIDs; empty is invalid. Structural parsing is not ownership, provider proof or canonical-source policy.
func ParseAccountID ¶
ParseAccountID validates structure without normalizing or changing the ID.
type AccountLinkChange ¶
type AccountLinkChange struct {
Mode AccountLinkMode
Account Account
Method *LoginMethod
Reason PolicyReason
ExpectedUserVersion uint64
ExpectedAccountVersion uint64
ExpectedSocialLinkVersion uint64
ExpectedCredentialVersion uint64
MatchedIdentifier IdentifierID
VerifiedCanonicalIdentifier string
ExpectedIdentifierAuthorityVersion uint64
ExpectedIdentifierVersion uint64
ExpectedVerificationVersion uint64
}
AccountLinkChange is exact, bounded intent. Account.Version must be one more than ExpectedAccountVersion, which is zero only for a never-used record ID. Nonzero history is retained after unlink; relinking requires fresh evidence and the current tombstone fence, not a stale callback or import assertion. Method optionally attaches an owner-validated provider credential; nil is a data-only link and must not change credential authority. Do not mutate input during calls. A change is neither a provider proof nor authorization.
Implicit linking requires all three identifier fences and an exact canonical value independently established from a fresh verified provider claim under registered provider semantics. Other modes must omit those fields. An administrative reason is a registered policy token, not free-form evidence.
type AccountLinkCommand ¶
type AccountLinkCommand struct {
Binding CommandBinding
Change AccountLinkChange
Proof capability.Grant
SessionID string
SessionVersion uint64
PreAuthTransactionID PreAuthTransactionID
}
AccountLinkCommand is frozen structural intent for the sole durable owner. Proof is the canonical verified capability grant, not caller proof material. Trusted feature composition independently verifies registered provider subject, canonical verified claims and actor session/consent (or implicit pre-auth mapping) before issuance by the configured identity authority. This command and its constructor do not mint that authority. The adapter must repeat fresh time, provider enablement, policy/session/identifier and one-use checks under locks, then atomically consume proof/risk with all mutation participants.
type AccountLinkConfig ¶
type AccountLinkConfig struct {
Query UserQueryConfig
ProofIssuer string
ProofAudience string
MaximumProofAge time.Duration
AllowAdministrative bool
AdministrativeReasons []PolicyReason
AllowImplicit bool
ImplicitActorID ActorID
}
AccountLinkConfig freezes exact proof authority and opt-in policy paths. MaximumProofAge is positive and at most five minutes. Administrative reasons are 1..32 unique safe registered tokens when enabled, absent when disabled. Implicit linking requires one exact trusted workload actor ID; enabling a mode or naming an actor never grants authorization or verified provider proof.
type AccountLinkMode ¶
type AccountLinkMode uint8
AccountLinkMode is a closed policy path, never a role or authority grant.
const ( AccountLinkExplicit AccountLinkMode = iota + 1 AccountLinkImplicit AccountLinkAdministrative )
type AccountLinkMutation ¶
type AccountLinkMutation struct {
Access AccountAccessSnapshot
Account Account
SocialLinkVersion uint64
CredentialVersion uint64
AddsCredential bool
}
AccountLinkMutation is copied proposed next state, never a durable receipt. AddsCredential advances credential authority once, including a currently unusable provider credential. Data-only links preserve that dimension.
func ApplyAccountLink ¶
func ApplyAccountLink(s AccountLinkState, c AccountLinkChange, now time.Time) (AccountLinkMutation, error)
ApplyAccountLink computes the identity-owned pure next state. It never transfers or merges an already-owned provider subject, including same-user duplicate links. Implicit linking requires a current verified email record and all exact authority/record/verification fences; email matching alone does not establish provider evidence. Existing access methods are conserved. Inputs are not mutated and errors return no partial state.
The platform durable owner checks exact same-command replay first, then locks tenant provider-subject uniqueness (including absent keys), record/tombstone, current primary eligibility/identifiers and all authority dimensions. It must revalidate configured provider proof, current policy, fresh actor session or pre-auth binding, and consume applicable proof/risk with state, audit/events, token-vault participant and original receipt atomically. Canonical provider registration and provider ceremonies belong to their feature owners. This function neither authorizes nor proves those durable/cryptographic effects.
Example ¶
package main
import (
"fmt"
"time"
identity "github.com/faustbrian/go-identity"
)
func main() {
// This is locked primary state, not a caller's claim of provider ownership.
user := identity.User{ID: "user", TenantID: "tenant", Status: identity.StatusActive, Version: 1}
account := identity.Account{ID: "account", TenantID: "tenant", UserID: "user", Provider: "example", Issuer: "https://issuer.example", Subject: "provider-subject", Version: 1}
change := identity.AccountLinkChange{Mode: identity.AccountLinkExplicit, Account: account, ExpectedUserVersion: 1, ExpectedSocialLinkVersion: 1, ExpectedCredentialVersion: 1}
state := identity.AccountLinkState{Access: identity.AccountAccessSnapshot{User: user}, Candidate: account, SocialLinkVersion: 1, CredentialVersion: 1}
next, err := identity.ApplyAccountLink(state, change, time.Date(2026, 10, 2, 8, 0, 0, 0, time.UTC))
if err != nil {
panic(err)
}
// Data-only linking does not manufacture a usable login credential. The
// platform command owner still authorizes, consumes proof/risk and commits.
fmt.Println(next.Access.User.Version, next.SocialLinkVersion, next.CredentialVersion, next.AddsCredential)
}
Output: 2 2 1 false
type AccountLinkProofSpec ¶
type AccountLinkProofSpec struct {
Command AccountLinkCommand
Issuer string
Audience string
ID string
IssuedAt time.Time
ExpiresAt time.Time
}
AccountLinkProofSpec is bounded unsigned issuance intent, not verified evidence. Command.Proof must be zero. Its issuer/ID/time and exact actor/ provider/identifier/continuation bindings come from trusted feature ceremony composition, never caller assertions or matching profile email alone.
type AccountLinkQuery ¶
type AccountLinkQuery struct {
Account Account
Mode AccountLinkMode
}
AccountLinkQuery binds a complete primary lookup to exact candidate metadata. Repositories retain record/tombstone and subject-key authority after unlink; they never treat absence from a user's account list as tenant-wide absence.
type AccountLinkReceipt ¶
type AccountLinkReceipt struct {
AccountID AccountID
Mode AccountLinkMode
ExpectedAccountVersion uint64
ExpectedSocialLinkVersion uint64
ExpectedCredentialVersion uint64
AccountVersion uint64
SocialLinkVersion uint64
CredentialVersion uint64
AddsCredential bool
}
AccountLinkReceipt is immutable local admission metadata. It is not provider network success, current authentication authority or lifecycle acknowledgement.
type AccountLinkRecoveryRequest ¶
type AccountLinkRecoveryRequest struct {
CommandID CommandID
TenantID TenantID
UserID UserID
AccountID AccountID
Mode AccountLinkMode
ActorScope authorization.DecisionContext
}
AccountLinkRecoveryRequest grants no access merely by possession of an ID. Current policy must authorize the original target/account/mode/actor scope.
type AccountLinkRepository ¶
type AccountLinkRepository interface {
GetAccountLinkState(context.Context, AccountLinkQuery) (AccountLinkState, error)
}
AccountLinkRepository owns bounded consistent primary reads, including exact tenant/provider/issuer/subject collision, tombstone and implicit identifier authority. It must honor concurrent bounded contexts; no provider I/O occurs.
type AccountLinkRequest ¶
type AccountLinkRequest struct {
CommandID CommandID
Change AccountLinkChange
Proof capability.Proof
SessionID string
SessionVersion uint64
PreAuthTransactionID PreAuthTransactionID
ActorScope authorization.DecisionContext
CorrelationID string
}
AccountLinkRequest is trusted core composition input, never HTTP JSON or a caller claim of verified provider email/freshness. Preserve it across retries. Proof is purpose/target/actor/command/continuation-bound signed one-use evidence issued only after the feature's actual proof ceremony and admitted policy.
type AccountLinkResult ¶
type AccountLinkResult struct {
CommandID CommandID
CommitOutcome CommitOutcome
AccountID AccountID
Version uint64
}
AccountLinkResult conserves the authoritative commit observation. Known commitment remains known when output is withheld. Unknown carries no claimed record/version success and is recovered, not silently retried under a new ID.
type AccountLinkService ¶
type AccountLinkService struct {
// contains filtered or unexported fields
}
AccountLinkService owns identity admission/recovery, not provider ceremonies, tokens, transactions, goroutines or a second link store. Dependencies are trusted composition capabilities and must honor bounded concurrent calls.
func NewAccountLinkService ¶
func NewAccountLinkService(repo AccountLinkRepository, uow UnitOfWork, auth authorization.Service, redact RedactFunc, caps capability.Service, c AccountLinkConfig) (*AccountLinkService, error)
NewAccountLinkService validates and copies configuration without external I/O.
func (*AccountLinkService) AccountLink ¶
func (s *AccountLinkService) AccountLink(ctx context.Context, r AccountLinkRequest) (out AccountLinkResult, err error)
AccountLink verifies signed intent before primary lookup and delegates exact same-command replay/CAS/atomic effects to the sole UnitOfWork. Verify never consumes the capability. Primary lookup is admission only; the durable owner repeats authoritative collision, eligibility, proof and policy checks under its shared lock/unique-index boundary before applying any state.
func (*AccountLinkService) RecoverAccountLink ¶
func (s *AccountLinkService) RecoverAccountLink(ctx context.Context, r AccountLinkRecoveryRequest) (out AccountLinkResult, err error)
RecoverAccountLink performs only scoped primary receipt recovery under current policy. It neither re-executes nor consumes proof, mutates links or calls providers.
type AccountLinkState ¶
type AccountLinkState struct {
Access AccountAccessSnapshot
Candidate Account
RecordVersion uint64
SocialLinkVersion uint64
CredentialVersion uint64
SubjectOwner *Account
Identifiers *IdentifierState
}
AccountLinkState is one exact consistent primary lookup, not a client claim. Candidate binds absence/collision observations to the requested exact record and tenant/provider/issuer/subject key. SubjectOwner is nil only for proven absence under that key; a foreign owner's safe metadata may be retained internally but never disclosed. RecordVersion retains the candidate ID's tombstone history. SocialLinkVersion is the exact candidate connection scope; CredentialVersion is the tenant/user credential authority dimension. Identifiers is mandatory for implicit linking and shares the exact user aggregate with Access. Snapshots are immutable during a call.
type AccountListRequest ¶
type AccountListRequest struct {
TenantID TenantID
UserID UserID
ActorScope authorization.DecisionContext
}
AccountListRequest is a trusted core current-human-subject read. ActorScope must come from authenticated composition, never client JSON or a role label.
type AccountListResult ¶
AccountListResult contains at most 100 permission-filtered safe records. Empty success is an explicit non-nil empty slice. NextCursor is reserved for stable pagination and remains empty in this bounded complete-read profile.
type AccountQuery ¶
AccountQuery is one exact primary partition read, bounded to MaximumAccounts. The repository must not truncate: more than the bound is an unavailable projection until stable account pagination is implemented.
type AccountRepository ¶
type AccountRepository interface {
ListAccounts(context.Context, AccountQuery) (AccountSnapshot, error)
}
AccountRepository owns concurrent-safe, bounded consistent primary listing. Return ErrUserAbsent for missing scope. Returned slices are immutable during a call; the service privately copies output. No provider network work occurs.
type AccountService ¶
type AccountService struct {
// contains filtered or unexported fields
}
AccountService owns bounded account read policy, not link authority, provider tokens, sessions, goroutines or transactions. Dependencies must be concurrency-safe.
func NewAccountService ¶
func NewAccountService(repo AccountRepository, authorize authorization.Service, redact RedactFunc, config UserQueryConfig) (*AccountService, error)
NewAccountService freezes validated query policy without I/O. Typed-nil repositories and authorization, missing callbacks and unbounded config fail.
func (*AccountService) AccountList ¶
func (s *AccountService) AccountList(ctx context.Context, req AccountListRequest) (result AccountListResult, err error)
AccountList authorizes before primary access, then again against current user state and each owned account. Denied rows are omitted without exposing counts. Invalid or unavailable policy/projection aborts the whole result. Clock is sampled once; no caller-supplied identity metadata becomes policy evidence.
type AccountSnapshot ¶
AccountSnapshot is one consistent user/account primary projection, ordered by account ID. It must not mix transactions, tenant partitions or cache versions.
type AccountUnlinkChange ¶
type AccountUnlinkChange struct {
TenantID TenantID
UserID UserID
AccountID AccountID
ExpectedUserVersion uint64
ExpectedAccountVersion uint64
ExpectedSocialLinkVersion uint64
ExpectedCredentialVersion uint64
}
AccountUnlinkChange specifies exact optimistic fences for one unlink. It is structural intent, not authorization, freshness or a command receipt. The command owner authorizes and validates fresh subject/session/credential proof independently, then locks primary state and supplies it to ApplyAccountUnlink.
type AccountUnlinkCommand ¶
type AccountUnlinkCommand struct {
Binding CommandBinding
Change AccountUnlinkChange
Proof capability.Grant
SessionID string
SessionVersion uint64
RevokeProvider bool
}
AccountUnlinkCommand is structural adapter input, not independently minted authority. Proof is the canonical authenticated capability grant. The trusted service verifies its configured authority first. The durable owner must check replay before CAS, revalidate time/session/credential/policy bindings under locks, reserve/finalize its single use with the mutation, repeat final-access eligibility and atomically write tombstone, audit, authority events, provider cleanup intent and original receipt. Never serialize a bearer into a receipt.
type AccountUnlinkConfig ¶
type AccountUnlinkConfig struct {
Query UserQueryConfig
ProofIssuer, ProofAudience string
MaximumProofAge time.Duration
}
AccountUnlinkConfig pins a single trusted capability issuer and audience. MaximumProofAge is positive and at most fifteen minutes; no implicit defaults.
type AccountUnlinkMutation ¶
type AccountUnlinkMutation struct {
Access AccountAccessSnapshot
Removed Account
TombstoneVersion uint64
SocialLinkVersion uint64
CredentialVersion uint64
InvalidatesCredential bool
}
AccountUnlinkMutation is a privately copied proposed next state, not a durable outcome. Removed identifies the exact original link; TombstoneVersion must remain durable after removal, preventing stale callbacks from restoring it. SocialLinkVersion always advances. CredentialVersion advances exactly once only when an authentication link was removed, even if already expired. The user aggregate advances without changing the separate user-authority dimension. Provider cleanup and session revocation are not claimed complete.
func ApplyAccountUnlink ¶
func ApplyAccountUnlink(state AccountUnlinkState, change AccountUnlinkChange, now time.Time) (AccountUnlinkMutation, error)
ApplyAccountUnlink computes one all-or-nothing identity-owned transition from locked current state. It rechecks final access rather than trusting an earlier plan, fences aggregate/account/social-link/credential versions and removes all target-dependent credentials. It performs no I/O, mutates no input and owns no locks or goroutines. Do not mutate supplied slices concurrently with a call.
The platform durable command owner must check same-command replay first, establish exact authorization/freshness and authoritative eligibility under locks, then persist this state, tombstone, authority events, audit, cleanup intents and original command receipt atomically with applicable one-use proofs/risk. This function alone neither consumes proofs nor proves a commit. Errors return no partial mutation. Clock is one trusted owner sample; expiry is exclusive. Provider credentials remain with their owner until enlisted deletion/revocation is durably initiated, never discarded by this pure step.
Example ¶
package main
import (
"fmt"
"time"
identity "github.com/faustbrian/go-identity"
)
func main() {
// Trusted command composition obtains this complete snapshot under its
// durable locks, after authorization and fresh proof verification.
state := identity.AccountUnlinkState{
AccountID: "provider-account", SocialLinkVersion: 1, CredentialVersion: 1,
Access: identity.AccountAccessSnapshot{
User: identity.User{ID: "user-a", TenantID: "tenant-a", Status: identity.StatusActive, Version: 1},
Accounts: []identity.Account{{ID: "provider-account", TenantID: "tenant-a", UserID: "user-a", Provider: "example", Issuer: "https://issuer.example", Subject: "provider-subject", Version: 1}},
Methods: []identity.LoginMethod{{Credential: identity.CredentialRef{ID: "password-a", TenantID: "tenant-a", UserID: "user-a", Kind: identity.CredentialPassword, Owner: "identity/password", Version: 1}, Usable: true}},
},
}
change := identity.AccountUnlinkChange{TenantID: "tenant-a", UserID: "user-a", AccountID: "provider-account", ExpectedUserVersion: 1, ExpectedAccountVersion: 1, ExpectedSocialLinkVersion: 1, ExpectedCredentialVersion: 1}
mutation, err := identity.ApplyAccountUnlink(state, change, time.Unix(100, 0))
if err != nil {
panic(err)
}
// The durable owner must still persist this with its audit and receipt.
fmt.Println(len(mutation.Access.Accounts), mutation.TombstoneVersion)
}
Output: 0 2
type AccountUnlinkPlan ¶
type AccountUnlinkPlan struct {
Account Account
RemainingUsableMethods uint16
InvalidatesCredential bool
}
AccountUnlinkPlan is the pure final-access decision for one exact owned link. It is not an Execute command, provider proof or permission. Removing an authentication link invalidates the credential dimension even if expired.
func CheckAccountUnlink ¶
func CheckAccountUnlink(snapshot AccountAccessSnapshot, tenant TenantID, user UserID, accountID AccountID, expectedVersion uint64, now time.Time) (AccountUnlinkPlan, error)
CheckAccountUnlink validates a complete owned primary snapshot and determines whether one versioned unlink would orphan access. It mutates nothing and grants no authority. Call after authorization and repeat under durable locks immediately before mutation with one trusted clock sample. The owner must fence user, account, social-link and applicable credential authority versions atomically with audit, cleanup intent and replay-safe command receipt.
Example ¶
package main
import (
"fmt"
"time"
identity "github.com/faustbrian/go-identity"
)
func main() {
// This is an authoritative owner's structural/policy check, not a public
// client's authorization proof. A durable mutation must repeat it under lock.
user := identity.User{ID: "user-a", TenantID: "tenant-a", Status: identity.StatusActive, Version: 2}
account := identity.Account{ID: "account-a", TenantID: user.TenantID, UserID: user.ID, Provider: "example", Issuer: "https://issuer.example", Subject: "subject-a", Version: 1}
snapshot := identity.AccountAccessSnapshot{User: user, Accounts: []identity.Account{account}, Methods: []identity.LoginMethod{
{Credential: identity.CredentialRef{ID: "password-a", TenantID: user.TenantID, UserID: user.ID, Kind: identity.CredentialPassword, Owner: "identity/password", Version: 1}, Usable: true},
}}
plan, err := identity.CheckAccountUnlink(snapshot, user.TenantID, user.ID, account.ID, 1, time.Date(2026, 10, 1, 12, 0, 0, 0, time.UTC))
if err != nil {
panic(err)
}
fmt.Println(plan.RemainingUsableMethods, plan.InvalidatesCredential)
}
Output: 1 false
type AccountUnlinkQuery ¶
AccountUnlinkQuery is an exact bounded consistent primary partition read. It must include tombstone social-link authority after removal for replay.
type AccountUnlinkReceipt ¶
type AccountUnlinkReceipt struct {
AccountID AccountID
ExpectedAccountVersion, ExpectedSocialLinkVersion, ExpectedCredentialVersion uint64
TombstoneVersion, SocialLinkVersion, CredentialVersion uint64
InvalidatesCredential bool
ProviderOutcome ProviderRevocationOutcome
}
AccountUnlinkReceipt is the immutable local unlink admission. These positive next versions and the removed account's tombstone are persisted atomically. ProviderOutcome is initial pending/not-requested, not current external state.
type AccountUnlinkRecoveryRequest ¶
type AccountUnlinkRecoveryRequest struct {
CommandID CommandID
TenantID TenantID
UserID UserID
AccountID AccountID
ActorScope authorization.DecisionContext
}
AccountUnlinkRecoveryRequest grants no continuation authority by ID alone. Current exact subject policy governs disclosure of the original receipt.
type AccountUnlinkRepository ¶
type AccountUnlinkRepository interface {
GetAccountUnlinkState(context.Context, AccountUnlinkQuery) (AccountUnlinkState, error)
}
AccountUnlinkRepository owns primary user/account/eligibility snapshots and tombstones, not provider network work. Implementations honor bounded contexts and concurrent calls. ErrUserAbsent has no public enumeration distinction.
type AccountUnlinkRequest ¶
type AccountUnlinkRequest struct {
CommandID CommandID
Change AccountUnlinkChange
SessionID string
SessionVersion uint64
Proof capability.Proof
RevokeProvider bool
ActorScope authorization.DecisionContext
CorrelationID string
}
AccountUnlinkRequest is trusted core input, not a public JSON shape. Session and actor bindings come from authenticated composition, never caller claims. Retain command/change/session/proof/provider choice across retries.
type AccountUnlinkResult ¶
type AccountUnlinkResult struct {
CommandID CommandID
CommitOutcome CommitOutcome
Version uint64
ProviderOutcome ProviderRevocationOutcome
}
AccountUnlinkResult distinguishes durable observation from permitted output. Unknown/withheld output carries no version/provider success. Committed remains committed even when cancellation or redaction withholds its projection.
type AccountUnlinkService ¶
type AccountUnlinkService struct {
// contains filtered or unexported fields
}
AccountUnlinkService owns core admission, scoped recovery and observation. It owns no store, transaction, locks, goroutines or provider I/O. Dependencies are trusted composition capabilities and must honor concurrent bounded calls.
func NewAccountUnlinkService ¶
func NewAccountUnlinkService(repo AccountUnlinkRepository, uow UnitOfWork, auth authorization.Service, redact RedactFunc, caps capability.Service, config AccountUnlinkConfig) (*AccountUnlinkService, error)
NewAccountUnlinkService validates dependencies/configuration without I/O.
func (*AccountUnlinkService) AccountUnlink ¶
func (s *AccountUnlinkService) AccountUnlink(ctx context.Context, r AccountUnlinkRequest) (out AccountUnlinkResult, err error)
AccountUnlink verifies exact one-use capability bindings and current primary admission, then delegates replay/CAS and atomic effects to the sole UnitOfWork. Signature validation never consumes the proof. Only same-command replay may pass older expected versions; the durable owner rejects new stale commands.
func (*AccountUnlinkService) RecoverAccountUnlink ¶
func (s *AccountUnlinkService) RecoverAccountUnlink(ctx context.Context, r AccountUnlinkRecoveryRequest) (out AccountUnlinkResult, err error)
RecoverAccountUnlink performs only scoped primary recovery; no proof is consumed, account changed, new command allocated or provider call made.
type AccountUnlinkState ¶
type AccountUnlinkState struct {
Access AccountAccessSnapshot
AccountID AccountID
SocialLinkVersion uint64
CredentialVersion uint64
}
AccountUnlinkState is the complete primary state at the durable unlink lock boundary. AccountID binds SocialLinkVersion to that exact connection; CredentialVersion is the tenant/user credential authority dimension, not a credential record version. All versions are positive. Access must include every current account and owner-validated login eligibility observation. This projection is not an authentication proof and must never be client input.
type ActorID ¶
type ActorID string
ActorID identifies the authenticated policy viewer; it is not an identity proof.
type AfterHookInput ¶
type AfterHookInput struct {
Context OperationContext
Observation HookObservation
}
AfterHookInput contains the original operation and an owned outcome copy.
type AssessRiskFunc ¶
type AssessRiskFunc func(context.Context, RiskPolicyInput) (RiskPolicyDecision, error)
AssessRiskFunc is a concurrent-safe bounded pure risk callback.
type AttemptedCommitOutcome ¶
type AttemptedCommitOutcome string
AttemptedCommitOutcome distinguishes attempt observation from durable results. Unknown conserves uncertainty and must never be interpreted as rollback.
const ( AttemptedCommitOutcomeAttempted AttemptedCommitOutcome = "attempted" AttemptedCommitOutcomeNotCommitted AttemptedCommitOutcome = "not-committed" AttemptedCommitOutcomeCommitted AttemptedCommitOutcome = "committed" AttemptedCommitOutcomeUnknown AttemptedCommitOutcome = "unknown" )
type AttributeKind ¶
type AttributeKind string
AttributeKind is a closed lossless value kind. The empty kind is invalid.
const ( AttributeString AttributeKind = "string" AttributeBool AttributeKind = "bool" AttributeInt64 AttributeKind = "int64" AttributeTime AttributeKind = "time" // AttributeStringList is a list of at most 64 string scalars, not a scalar. AttributeStringList AttributeKind = "string-list" )
type AttributePrepareRequest ¶
type AttributePrepareRequest struct {
TenantID TenantID
UserID UserID
SchemaVersion uint32
Updates []AttributeUpdate
Context authorization.DecisionContext
}
AttributePrepareRequest is trusted command composition, not a client-decoded authorization context. Supported actions are identity.user.create, identity.profile.update and identity.user.update-admin; only create fills absent defaults. SchemaVersion is exact, not a request to auto-migrate.
type AttributeProcessor ¶
type AttributeProcessor struct {
// contains filtered or unexported fields
}
AttributeProcessor validates, normalizes and authorizes command values. It owns no stores, transactions, goroutines or locks and is concurrent-safe if its injected dependencies are. Prepared values are NOT a proof or a durable mutation: the command owner must bind/authorize/version-fence/persist them atomically. Output permissions still require projection/redaction at reads.
func NewAttributeProcessor ¶
func NewAttributeProcessor(schema AttributeSchema, authorize authorization.Service, normalize NormalizeAttributeFunc, config AttributeProcessorConfig) (*AttributeProcessor, error)
NewAttributeProcessor validates and deep-copies composition without callbacks or I/O. A missing/typed-nil dependency, malformed schema or default is rejected.
func (*AttributeProcessor) Prepare ¶
func (p *AttributeProcessor) Prepare(ctx context.Context, req AttributePrepareRequest) (result []AttributeUpdate, err error)
Prepare returns ordered caller-owned values only if the whole request is valid and authorized at the configured revision. The operation and every field (including create defaults) require Allow. Self fields additionally require a user actor whose ID equals the target. Policy callbacks receive schema/field/class/sensitivity metadata, never attribute contents. Reserved metadata is replaced, not accepted from callers. No partial output survives a deny, cancellation, malformed callback output, dependency error or panic.
type AttributeProcessorConfig ¶
type AttributeProcessorConfig struct {
Clock clock.Clock
MaximumDuration time.Duration
PolicyVersion uint64
ValidateCanonicalUserID CanonicalUserIDValidator
ValidateValue ValidateAttributeFunc
}
AttributeProcessorConfig binds trusted time, policy revision and canonical directory-ID validation. MaximumDuration is positive and at most one minute; no implicit defaults. The processor samples Clock once per preparation.
type AttributeScalar ¶
type AttributeScalar struct {
Kind AttributeKind
String string
Bool bool
Int64 int64
Time time.Time
}
AttributeScalar is a tagged scalar. Only its selected arm may be populated; false, integer zero and empty string are valid present values. Time must be nonzero; preparation returns UTC. Strings are valid UTF-8 and at most 4096 bytes. There is deliberately no float conversion or arbitrary JSON payload.
type AttributeSchema ¶
type AttributeSchema struct {
ID string
Version uint32
Fields []FieldPolicy
}
AttributeSchema declares 1..128 unique fields and positive migration version. NewAttributeProcessor snapshots it; later caller changes have no effect.
func (AttributeSchema) Validate ¶
func (s AttributeSchema) Validate() error
Validate checks a schema structurally without granting input, write or read authority. Scalar kinds require scalar cardinality; only StringList uses list cardinality. Normalization applies only to strings. Defaults across the schema and values across one command have a 256 KiB string payload budget.
Example ¶
package main
import (
"fmt"
"github.com/faustbrian/go-identity"
)
func main() {
schema := identity.AttributeSchema{ID: "profile", Version: 1, Fields: []identity.FieldPolicy{{
Name: "display_name", Kind: identity.AttributeString, Cardinality: identity.CardinalityScalar,
Normalization: identity.NormalizeNone, InputPermission: identity.FieldWrite,
OutputPermission: identity.FieldRead, WriteAuthorization: identity.FieldWriteSelf,
Sensitivity: identity.SensitivityPersonal, MigrationVersion: 1,
}}}
fmt.Println(schema.Validate())
}
Output: <nil>
type AttributeUpdate ¶
type AttributeUpdate struct {
Name string
Value AttributeValue
}
AttributeUpdate is one named whole-value replacement, not a patch language.
type AttributeValue ¶
type AttributeValue struct {
Kind AttributeKind
Scalar AttributeScalar
List []AttributeScalar
}
AttributeValue is one scalar or a homogeneous bounded string list. An empty Kind is absent only for an entirely zero default; it is invalid in updates. Configure/submit values without concurrent mutation. Results own their lists.
type BeforeHookDecision ¶
type BeforeHookDecision string
BeforeHookDecision is a closed explicit decision; zero is invalid.
const ( BeforeHookContinue BeforeHookDecision = "continue" BeforeHookReject BeforeHookDecision = "reject" )
type BeforeHookInput ¶
type BeforeHookInput struct {
Context OperationContext
Fields []HookField
}
BeforeHookInput contains owned metadata copies and the immutable operation.
type BeforeHookResult ¶
type BeforeHookResult struct {
Decision BeforeHookDecision
Enrichments []HookEnrichment
Reasons []PolicyReason
}
BeforeHookResult is the ordered validated decision. Reject discards earlier enrichments; Reasons contain only registered non-secret diagnostic codes.
type CancelledError ¶
type CancelledError struct{}
CancelledError identifies cancellation without exposing dependency errors.
func (CancelledError) Error ¶
func (CancelledError) Error() string
func (CancelledError) Unwrap ¶
func (CancelledError) Unwrap() error
type CanonicalUserIDValidator ¶
CanonicalUserIDValidator validates a directory ID without replacing it. Composition may accept existing ULIDs. It must be bounded, side-effect-free and concurrency-safe; errors are redacted at the service boundary.
type Cardinality ¶
type Cardinality string
Cardinality distinguishes scalar presence from list presence. A nil list is absent; an allocated empty list is a valid explicit empty replacement.
const ( CardinalityScalar Cardinality = "scalar" CardinalityList Cardinality = "list" )
type CascadeID ¶
type CascadeID string
CascadeID is a canonical nonzero 128-bit random cascade identity. It is correlation, not authority. Retain it with its generation through cleanup.
func NewCascadeID ¶
NewCascadeID generates a cascade ID without exposing entropy failures.
func ParseCascadeID ¶
ParseCascadeID accepts only the canonical unpadded 22-byte representation.
type ClaimsPolicyDecision ¶
type ClaimsPolicyDecision struct {
Claims []TypedClaim
PolicyID string
PolicyVersion uint64
Reason PolicyReason
}
ClaimsPolicyDecision is a bounded copied mapping, not authenticated authority. Reason is mandatory even for an explicitly empty mapped claim set.
type ClaimsPolicyInput ¶
type ClaimsPolicyInput struct {
TenantID TenantID
ActorID ActorID
OperationID string
PolicyVersion uint64
Deadline time.Time
Issuer string
Subject string
Claims []TypedClaim
}
ClaimsPolicyInput binds verified provider data to trusted tenant/actor and exact operation/version. Issuer is a bounded absolute HTTPS URI without credentials, query or fragment; Subject is at most 512 bytes. It proves no provider authentication by itself. Claims must be an explicit bounded slice.
type Command ¶
type Command struct {
// contains filtered or unexported fields
}
Command is a closed immutable storage-neutral mutation. Its zero value is invalid. It exposes no transactions, arbitrary callbacks or participants. Formatting is always redacted and JSON serialization is forbidden. Adapter mapping uses the typed accessor, never reflection or command JSON. The adapter owns versioned keyed canonical fingerprints, reservations and durable replay. Kernel variants retain exact owned types; the explicit feature branch carries bounded named typed input for exhaustive feature-adapter schema mapping. It grants no generic callback, transaction, receipt or execution authority.
func BindPhonePasswordResetPreAuth ¶
func BindPhonePasswordResetPreAuth(original Command, cookie auth.BearerCredential) (Command, error)
BindPhonePasswordResetPreAuth retains the original browser-flow cookie with an exact joint phone-reset input or generated command. It returns a new immutable command, preserving every borrowed password/proof/code owner and leaving the original unchanged. Already-bound, legacy, mixed or zero commands and noncanonical cookies return zero Command and redacted InvalidInputError. Cookie syntax is canonical unpadded base64url for 32..64 bytes; only the native session owner may authenticate its original purpose, target and current row. Binding grants no verification or consumption authority and enables no flow.
func NewAccountLinkCommand ¶
func NewAccountLinkCommand(s AccountLinkCommand) (Command, error)
NewAccountLinkCommand snapshots validated intent. It grants no authority, canonicalization, provider verification, freshness or database transaction.
func NewAccountUnlinkCommand ¶
func NewAccountUnlinkCommand(s AccountUnlinkCommand) (Command, error)
NewAccountUnlinkCommand freezes validated intent. Construction does not authorize or establish freshness; only trusted composition crosses UnitOfWork.
func NewFeatureCommand ¶
func NewFeatureCommand(spec FeatureCommandSpec) (Command, error)
NewFeatureCommand validates and freezes structural feature input, copying every field and binary value. It conveys no authentication, authorization, current state, freshness or execution readiness. The sole durable owner must match the exact registered descriptor and validate the full feature schema before computing its keyed fingerprint and admitting any phase. Current kernel coordinator execution/receipt paths do not accept this variant. Invalid input returns redacted InvalidInputError; zero is invalid. Pure, bounded construction performs no I/O/callbacks and starts no goroutines.
Example ¶
package main
import (
"fmt"
"math"
"github.com/faustbrian/go-authorization/v3"
identity "github.com/faustbrian/go-identity"
)
func main() {
// Trusted adapter mapping, not authentication, authorization or issuance.
c, err := identity.NewFeatureCommand(identity.FeatureCommandSpec{
Operation: identity.FeatureOperation{Owner: "identity/session", OperationID: "identity.session.issue", SchemaID: "session-issue", SchemaVersion: 1, RecordRequirement: identity.FeatureRecordRequired},
Binding: identity.CommandBinding{
CommandID: "AQEBAQEBAQEBAQEBAQEBAQ", TenantID: "tenant-a", UserID: "user-a",
ActorID: "actor-a", ActorKind: authorization.SubjectUser,
OperationID: "identity.session.issue", RecordID: "session-a",
PolicyID: "session-policy", PolicyVersion: 1,
SchemaID: "session-issue", SchemaVersion: 1, CorrelationID: "correlation-a",
},
Fields: []identity.FeatureField{{Name: "authority.user-version", Value: identity.FeatureValue{Kind: identity.FeatureUint64, Uint64: math.MaxUint64}}},
})
if err != nil {
panic("invalid example command")
}
projection, _ := c.Feature() // trusted mapping only; never log the projection
fmt.Println(projection.Fields[0].Value.Uint64)
fmt.Println(c)
}
Output: 18446744073709551615 identity.Command(redacted)
func NewFeatureOneTimeCodeCommand ¶
func NewFeatureOneTimeCodeCommand(spec FeatureCommandSpec, code authentication.OneTimeCode) (Command, error)
NewFeatureOneTimeCodeCommand freezes structural feature intent and one opaque submitted code for a trusted native adapter. Code bytes never enter FeatureValue or FeatureCommandSpec, and Feature returns only the code-free metadata. This carries custody, not successful verification, authorization or one-time use. The owning feature validates its exact schema, scope and code profile; the sole durable coordinator binds the secret in its keyed command fingerprint. Unsupported one-time profiles must be rejected before durable admission.
The constructor validates nonzero code through a discarded bounded digest with a public validation-only key, never a stored verifier or authority key. It accepts no request-selected digest. Existing structural bounds, defensive copying and errors are identical to NewFeatureCommand; zero code returns InvalidInputError. It performs no IO or callbacks and is safe for immutable concurrent reads. Command copies retain the secret; discard every copy on a terminal outcome and retain only code-free recovery metadata on ambiguity. Go cannot guarantee complete erasure of immutable secret storage.
func NewFeatureOneTimeCodePreAuthCommand ¶
func NewFeatureOneTimeCodePreAuthCommand(spec FeatureCommandSpec, code authentication.OneTimeCode, cookie authentication.BearerCredential) (Command, error)
NewFeatureOneTimeCodePreAuthCommand freezes an OTP submission and its separate original pre-auth cookie in opaque command custody, never in scalar metadata. Cookie is the canonical unpadded base64url transport of 32..64 bytes. This validates syntax only: the native session/OTP owner must independently derive the named cookie commitment from the original flow, admit primary state and current policy, and consume atomically. Neither a cookie nor code is proof.
Existing one-time-code constructors remain unchanged. Invalid spec, zero code or malformed cookie returns zero Command and redacted InvalidInputError. No IO, callbacks, time samples or disclosure occur. Immutable copies are concurrency safe; discard every secret-bearing copy at terminal outcomes. Recovery uses code/cookie-free metadata; Go cannot guarantee immutable secret erasure.
func NewFeatureOneTimeCodeSessionCommand ¶
func NewFeatureOneTimeCodeSessionCommand(spec FeatureCommandSpec, code authentication.OneTimeCode, token authentication.BearerCredential) (Command, error)
NewFeatureOneTimeCodeSessionCommand freezes an OTP submission with a separate original session token in opaque custody, never in scalar metadata. Token must be canonical unpadded base64url of 32..64 bytes. It cannot create pre-auth cookie custody. This is syntax validation, not possession proof, authenticated provenance, active status or permission; native session admission must derive the lookup digest under the original retained key and compare primary owners. Invalid scope, zero code or malformed token returns a zero Command and redacted InvalidInputError. Construction is bounded and performs no IO or callbacks. Copies are immutable and safe for concurrent reads. Never retain, persist, export or log borrowed secrets beyond bounded use. Recovery uses code/token-free metadata; Go cannot guarantee complete immutable secret erasure.
func NewFeaturePasswordChangeCommand ¶
func NewFeaturePasswordChangeCommand(spec FeatureCommandSpec, encodedHash string, bearer authentication.BearerCredential, proof authentication.ReauthenticationProof) (Command, error)
NewFeaturePasswordChangeCommand freezes existing-password change metadata, encoded hash, original session bearer and the sole upstream reauthentication proof together. Only identity/password's record-required password-change v1 profile is admitted. Hash and bearer transport bounds are those documented by NewFeaturePasswordHashCommand and NewFeatureSessionCommand. Proof structure uses upstream authentication validation at its original issuance instant; tenant, subject and protected action must match the command and the proof purpose must be identity.password.verify. Original versions and nanoseconds are retained, not rounded or renewed. No current clock is sampled.
Construction grants no authentication or mutation authority: the native password owner must reverify the signed original proof, current source session, hash/HIBP/reuse policy and consume the proof atomically with the mutation and session effects. This transport does not verify a signature or consume a proof. Existing feature, hash-only and session accessors reject this disjoint variant; a native executor must explicitly bind all PasswordChangeCustody values into its keyed intent before admitting execution or recovery. Existing executors remain closed to it. Invalid input returns zero Command and redacted error.
Construction is bounded and pure, with no IO, callbacks or goroutines. Do not mutate inputs concurrently with construction. Copies are immutable and safe for concurrent reads; discard all secret-bearing copies after bounded use. Go cannot guarantee immutable string erasure. Never supply plaintext passwords.
func NewFeaturePasswordHashCommand ¶
func NewFeaturePasswordHashCommand(spec FeatureCommandSpec, encodedHash string) (Command, error)
NewFeaturePasswordHashCommand freezes existing-password change metadata and an encoded hash in separate opaque custody. Hash transport is 1..16384 visible ASCII bytes, preserved exactly, never normalized. These are storage transport bounds only: the password owner must independently parse the reviewed encoding under its primitive limits, enforce HIBP/reuse/reauthentication/session policy, and bind the actual hash into the sole coordinator's keyed command intent. This function does not hash, verify, validate an algorithm or grant authority.
Only identity/password's record-required identity.password.change profile is admitted. Unsupported signup/reset/rehash profiles and mixed OTP/bearer custody are not inferred. Invalid input returns zero Command and redacted InvalidInput. The legacy Feature accessor deliberately rejects this variant, preventing older coordinators from dropping material from command fingerprints. A native owner must explicitly select PasswordHashFeature and PasswordHash together. Construction performs no IO/callbacks and starts no goroutines. Command copies retain immutable verifier material; discard all copies after bounded use. Go cannot guarantee erasure of immutable strings. Never pass a plaintext password.
func NewFeaturePasswordResetCommand ¶
func NewFeaturePasswordResetCommand(spec FeatureCommandSpec, encodedHash string, proof capability.Proof) (Command, error)
NewFeaturePasswordResetCommand retains prepared replacement verifier material and the original upstream capability proof for a trusted native reset owner. Only identity/password's identity.password.reset-complete, password-reset-complete v1, record-required, user-targeted descriptor is supported. Hash transport is 1..16384 visible ASCII bytes, unchanged; proof transport is 32..4096 canonical bytes observed through upstream ValidateBounds. Invalid input returns a zero Command and redacted InvalidInputError without transferring the proof.
This is structural custody, not signature validation, current account/factor authority, HIBP/hash policy, issuance provenance or permission to execute. The native owner must bind both original values into its keyed intent and reserve, mutate credentials, apply session effects and finalize capability use in one recoverable transaction. Existing execution paths reject this variant.
Metadata and verifier are frozen; proof copies retain upstream shared lifetime semantics. Transfer through any alias invalidates all aliases. A successful bounds observation is not a liveness lease. No token bytes are copied, exposed, verified or transferred here. Construction performs no IO, callbacks or clock reads. Concurrent reads and upstream transfers are safe; callers must discard all secret-bearing copies after bounded use. Never pass a plaintext password.
func NewFeaturePasswordResetInputCommand ¶
func NewFeaturePasswordResetInputCommand(spec FeatureCommandSpec, password primitive.Secret, proof capability.Proof) (Command, error)
NewFeaturePasswordResetInputCommand freezes original password-reset input before a replacement verifier exists. It admits only the exact user-targeted password-reset-complete v1 descriptor. The password is 1..1 MiB and proof transport is 32..4096 canonical bytes; workflow policy may narrow both. No bytes are copied, normalized, hashed, verified or consumed. Construction grants no issuance provenance, current recovery authority or execution.
This variant is preparation-only. The existing journal binds original borrowed password/proof custody before acknowledged, admission-gated generation. Only NewFeaturePasswordResetCommand selects the generated verifier for execution. Callers must keep both owners alive during bounded use and destroy their password afterward. Copies share terminal Secret destruction and upstream Proof transfer. Structural presence is not a liveness lease. No IO, callbacks, clocks or goroutines run; errors return zero and redacted InvalidInputError.
func NewFeaturePasswordSigninCommand ¶
func NewFeaturePasswordSigninCommand(spec FeatureCommandSpec, password primitive.Secret, cookie authentication.BearerCredential) (Command, error)
NewFeaturePasswordSigninCommand freezes structural signin metadata with the existing primitive-owned password and original pre-auth cookie. The closed native profiles are identity/password, identity.password.signin, password-signin v1; identity/username, identity.username.signin, username-signin v1; and identity/phone, identity.phone.password-signin, phone-password-signin v1, all record-omitted with explicit user or anonymous-flow scope. This internal adapter schema is distinct from the public request schema. Cookie transport uses NewFeaturePreAuthCommand's canonical 32..64-byte base64url bounds.
Password length must be 1..1 MiB. No bytes are borrowed, copied, normalized, hashed or compared; copies retain the same Secret owner. The caller must Destroy that owner after bounded native execution, including failure. Length validation is not a liveness lease: destruction invalidates later borrowing. Construction grants no authentication, flow possession or execution authority. The native password owner must perform actual comparison, policy/current fences, keyed intent binding and same-commit effects under the coordinator.
Legacy Feature/OTP/hash/change/bearer accessors reject this disjoint variant rather than silently omitting the password from intent. Only the paired PasswordSigninFeature and PasswordSigninCustody accessors select it. Recovery must use secret-free correlation, never this command. Invalid inputs return zero Command and redacted InvalidInputError. No IO or callbacks run.
func NewFeaturePasswordSignupCommand ¶
func NewFeaturePasswordSignupCommand(spec FeatureCommandSpec, encodedHash string, cookie authentication.BearerCredential) (Command, error)
NewFeaturePasswordSignupCommand freezes prepared encoded verifier material and the original pre-auth cookie in paired opaque custody. The closed native profiles are identity/password, identity.password.signup, password-signup v1 and identity/username, identity.username.signup, username-signup v1, record omitted, with explicit user or anonymous-flow scope. Hash transport is exactly 1..16384 visible ASCII bytes; cookie transport follows NewFeaturePreAuthCommand. Neither is normalized. Never pass plaintext here.
This is transport, not hash-policy/HIBP approval, flow possession, risk admission, field permission or authentication. The native password owner must independently validate preparation, reserve the original flow/risk, bind both custody values into keyed intent and commit all required effects under the sole coordinator. No IO, callbacks, clocks or goroutines run. Legacy accessors reject this disjoint variant rather than dropping secrets. Invalid input returns zero Command and redacted InvalidInputError. Copies share immutable custody and support concurrent reads; discard them after bounded use. Go cannot guarantee erasure of immutable verifier/bearer strings.
func NewFeaturePasswordSignupInputCommand ¶
func NewFeaturePasswordSignupInputCommand(spec FeatureCommandSpec, password primitive.Secret, cookie authentication.BearerCredential) (Command, error)
NewFeaturePasswordSignupInputCommand freezes original anonymous signup input before a verifier exists. The closed profiles are identity/password, identity.password.signup, password-signup v1, and identity/username, identity.username.signup, username-signup v1, both record-omitted with anonymous-flow scope. Native execution remains explicitly selected. Cookie transport follows NewFeaturePreAuthCommand's canonical base64url bounds. Password length must be 1..1 MiB; registration policy may narrow these bounds.
No password bytes are copied, normalized, hashed or compared. Copies share the primitive Secret owner, which the caller must Destroy after bounded use on every path. Destruction invalidates borrowing, not safe metadata. This command is preparation input, never the generated hash/cookie execution variant and never a recovery input. Construction grants no flow possession, password-policy approval, authorization or permission to execute. The native journal must bind original custody before acknowledged generation, then restore the generated verifier through NewFeaturePasswordSignupCommand.
Only PasswordSignupInputFeature and PasswordSignupInputCustody select it. Legacy and generated-command accessors deny rather than discard the original password. Invalid input returns zero Command and redacted InvalidInputError. No IO, callbacks, clocks or goroutines run.
func NewFeaturePhonePasswordResetCommand ¶
func NewFeaturePhonePasswordResetCommand(spec FeatureCommandSpec, encodedHash string, proof capability.Proof, phoneCode, totpCode auth.OneTimeCode) (Command, error)
NewFeaturePhonePasswordResetCommand retains the generated replacement verifier and all three original proof/code inputs for the same explicit phone profile. Verifier transport is 1..16384 visible ASCII bytes, unchanged, never plaintext. It does not screen or hash a password. Secret and authorization responsibilities, lifetimes and atomicity are otherwise identical to the input constructor. Preparation input and generated execution remain mutually exclusive; native owners must preserve every original input rather than issue substitute proof.
func NewFeaturePhonePasswordResetInputCommand ¶
func NewFeaturePhonePasswordResetInputCommand(spec FeatureCommandSpec, password primitive.Secret, proof capability.Proof, phoneCode, totpCode auth.OneTimeCode) (Command, error)
NewFeaturePhonePasswordResetInputCommand freezes a joint original password, canonical reset proof, phone OTP and independent TOTP submission. Only the user-targeted identity/phone password-reset-complete.native-v1 descriptor is supported. This is structural custody, never proof of successful verification, carrier safety, risk admission or permission to consume any artifact.
Password bounds are 1..1 MiB; proof transport is 32..4096 canonical bytes. Codes retain upstream opaque custody and structural bounds. No password or token bytes are copied, normalized, exposed, verified or consumed. Callers keep borrowed owners alive during bounded use and destroy the password after use. Copies share terminal password destruction and proof transfer.
The native coordinator must explicitly bind all four inputs, original pre-auth/phone/factor authority and completion-only risk evidence. Replacement, OTP/TOTP replay advancement, capability/risk consumption and session revocation must commit atomically. Legacy email-reset and single-code accessors deny; construction enables no workflow or endpoint. Errors are redacted; no IO, callbacks, clocks or goroutines run. Immutable concurrent reads are safe.
func NewFeaturePreAuthCommand ¶
func NewFeaturePreAuthCommand(spec FeatureCommandSpec, cookie authentication.BearerCredential) (Command, error)
NewFeaturePreAuthCommand freezes a feature command with only its submitted original pre-auth cookie, not an OTP submission. Cookie must be canonical unpadded base64url of 32..64 bytes. Construction validates syntax and scope, not possession, active flow, current authority or permission. The native owner must independently derive the original cookie commitment and check primary state before mutation; a cookie must never imply authentication. Invalid input returns zero Command and redacted InvalidInputError. No IO, clocks or callbacks run. Immutable copies support concurrent reads; discard secret-bearing copies after bounded use. Recovery uses secret-free metadata.
func NewFeatureRecoveryCodePreAuthCommand ¶
func NewFeatureRecoveryCodePreAuthCommand(spec FeatureCommandSpec, code authentication.RecoveryCode, cookie authentication.BearerCredential) (Command, error)
NewFeatureRecoveryCodePreAuthCommand freezes a distinct recovery-code submission and its original canonical browser cookie for a trusted adapter. Neither secret enters scalar Feature metadata. Construction validates syntax only; the native owner must authenticate the original primary/continuation, compare the digest and burn the code with session effects in one transaction. This never coerces recovery material to OTP or grants factor assurance.
Zero code, malformed cookie or invalid bounded spec returns zero Command and redacted InvalidInputError. Validation uses a discarded public-key digest, never a stored verifier. No IO, clocks or caller callbacks run. Immutable copies share secret custody and are safe for concurrent reads; discard every copy on terminal outcomes. Durable recovery uses secret-free metadata. Go cannot guarantee complete erasure of immutable credential storage.
func NewFeatureSessionCommand ¶
func NewFeatureSessionCommand(spec FeatureCommandSpec, token authentication.BearerCredential) (Command, error)
NewFeatureSessionCommand freezes a feature command with only its submitted original session token, not an OTP or authenticated proof. Token has the same bounded canonical transport as NewFeaturePreAuthCommand but remains a disjoint custody variant even when bytes match. The native session owner must derive the lookup digest under the original retained key and recheck current primary ownership, freshness and authority. Syntax alone confers none of these. Invalid input returns zero Command and redacted InvalidInputError. It performs no IO or callbacks. Immutable copies support concurrent reads; never persist, log or serialize borrowed bearer copies. Go cannot guarantee their erasure.
func NewIdentifierCommand ¶
func NewIdentifierCommand(c IdentifierCommand) (Command, error)
NewIdentifierCommand validates exact signed intent and snapshots the command. It does not verify cryptography or consume proof; trusted service composition verifies configured issuer/audience and freshness before crossing UnitOfWork.
func NewPrivacyExportRequestCommand ¶
func NewPrivacyExportRequestCommand(c PrivacyExportRequestCommand) (Command, error)
NewPrivacyExportRequestCommand validates and freezes exact signed metadata. It does not verify issuer trust, proof time, session freshness, authorization or storage. It never consumes proof. Only actual admission through the owned service and durable UnitOfWork can make an export runnable. This metadata-only constructor cannot manufacture original opaque proof custody.
func NewProfileUpdateCommand ¶
func NewProfileUpdateCommand(spec ProfileUpdateCommand) (Command, error)
NewProfileUpdateCommand bounds and copies intent without granting authority.
Example ¶
package main
import (
"fmt"
"github.com/faustbrian/go-authorization/v3"
identity "github.com/faustbrian/go-identity"
)
func main() {
command, err := identity.NewProfileUpdateCommand(identity.ProfileUpdateCommand{
Binding: identity.CommandBinding{CommandID: "AQEBAQEBAQEBAQEBAQEBAQ", TenantID: "tenant-a", UserID: "user-a", ActorID: "user-a", ActorKind: authorization.SubjectUser, OperationID: "identity.profile.update", PolicyID: "profile-policy", PolicyVersion: 1, SchemaID: "profile", SchemaVersion: 1, CorrelationID: "correlation-a"},
ExpectedVersion: 2, Name: "example",
})
if err != nil {
panic(err)
}
_, ok := command.UpdateProfile()
fmt.Println(command, ok)
}
Output: identity.Command(redacted) true
func NewUserCreationCommand ¶
func NewUserCreationCommand(spec CreateUserCommand) (Command, error)
NewUserCreationCommand validates and snapshots a creation's structural input. It does NOT authorize, canonicalize directory IDs or validate a field schema. Trusted composition uses UserCreationService before crossing UnitOfWork.
Example ¶
package main
import (
"fmt"
"github.com/faustbrian/go-authorization/v3"
"github.com/faustbrian/go-identity"
)
func main() {
id, err := identity.NewCommandID()
if err != nil {
panic(err)
}
command, err := identity.NewUserCreationCommand(identity.CreateUserCommand{
Binding: identity.CommandBinding{
CommandID: id, TenantID: "tenant-example", UserID: "user-example",
ActorID: "operator-example", ActorKind: authorization.SubjectServiceAccount,
OperationID: "identity.user.create", PolicyID: "directory-policy", PolicyVersion: 1,
SchemaID: "profile", SchemaVersion: 1, CorrelationID: string(id),
}, Status: identity.StatusActive,
})
if err != nil {
panic(err)
}
fmt.Printf("%#v\n", command)
}
Output: identity.Command(redacted)
func NewUserStatusCommand ¶
func NewUserStatusCommand(spec UserStatusCommand) (Command, error)
NewUserStatusCommand freezes structural lifecycle intent; it grants no authorization and does not replace trusted service or locked owner policy. Nonzero expiry must be microsecond-exact and within PostgreSQL years 1..9999.
Example ¶
package main
import (
"fmt"
"github.com/faustbrian/go-authorization/v3"
identity "github.com/faustbrian/go-identity"
)
func main() {
// Trusted composition authorizes and validates policy before sending this
// immutable intent to the durable owner. Construction grants no authority.
command, err := identity.NewUserStatusCommand(identity.UserStatusCommand{
Binding: identity.CommandBinding{
CommandID: "AQEBAQEBAQEBAQEBAQEBAQ", TenantID: "tenant-a",
UserID: "01ARZ3NDEKTSV4RRFFQ69G5FAV", ActorID: "actor-a",
ActorKind: authorization.SubjectUser, OperationID: "identity.user.suspend",
PolicyID: "identity-policy", PolicyVersion: 1,
SchemaID: "identity-lifecycle", SchemaVersion: 1, CorrelationID: "request-a",
},
ExpectedVersion: 12, ExpectedAuthorityVersion: 3, StatusPolicyVersion: 1,
TargetStatus: identity.StatusSuspended, Reason: "abuse",
})
if err != nil {
panic(err)
}
spec, ok := command.UserStatus()
fmt.Println(ok, len(spec.RequiredConsumers()))
fmt.Println(command)
}
Output: true 12 identity.Command(redacted)
func NewUserUpdateCommand ¶
func NewUserUpdateCommand(spec UpdateUserCommand) (Command, error)
NewUserUpdateCommand validates and privately copies an administrative update. It is not an authority issuer; use trusted UserUpdateAdminService composition.
Example ¶
package main
import (
"fmt"
"github.com/faustbrian/go-authorization/v3"
"github.com/faustbrian/go-identity"
)
func main() {
id, err := identity.NewCommandID()
if err != nil {
panic(err)
}
command, err := identity.NewUserUpdateCommand(identity.UpdateUserCommand{
Binding: identity.CommandBinding{CommandID: id, TenantID: "tenant-example", UserID: "user-example", ActorID: "operator-example", ActorKind: authorization.SubjectServiceAccount, OperationID: "identity.user.update-admin", PolicyID: "directory-policy", PolicyVersion: 1, SchemaID: "profile", SchemaVersion: 1, CorrelationID: string(id)},
ExpectedVersion: 2, Attributes: []identity.AttributeUpdate{{Name: "display_name", Value: identity.AttributeValue{Kind: identity.AttributeString, Scalar: identity.AttributeScalar{Kind: identity.AttributeString, String: "public-example"}}}},
})
if err != nil {
panic(err)
}
// Construction validates structure, not policy or permission to execute.
fmt.Printf("%#v\n", command)
}
Output: identity.Command(redacted)
func (Command) ChangeIdentifier ¶
func (c Command) ChangeIdentifier() (IdentifierCommand, bool)
ChangeIdentifier returns a private value copy for this variant only.
func (Command) CreateUser ¶
func (c Command) CreateUser() (CreateUserCommand, bool)
CreateUser returns a private copy and false for an invalid/zero command. Returned contents are for trusted adapters, never diagnostics or snapshots.
func (Command) Feature ¶
func (c Command) Feature() (FeatureCommandSpec, bool)
Feature returns an owned projection for trusted adapter schema mapping and false for zero, kernel, mixed or password-custody commands. Password owners must explicitly select their matching metadata/custody pair; older coordinators cannot silently omit verifier or submitted password material. Mutating returned fields or Bytes cannot change retained command intent. Copies of Command are immutable and safe for concurrent reads. The projection must never become a log, snapshot, public response or authentication decision. No callbacks or I/O run.
func (Command) IdentifierProof ¶
func (c Command) IdentifierProof() (capability.Proof, bool)
IdentifierProof returns optional request-memory custody of the original opaque proof attached by IdentifierService after admission. The boolean indicates presence, not validity or authorization. The transaction owner must reverify it with its configured capability service and reserve/consume atomically. Copies share the original proof's one-transfer lifetime; neither this accessor nor admission transfers or consumes it. NewIdentifierCommand constructs only metadata and does not attach custody. Never persist this proof.
func (Command) LinkAccount ¶
func (c Command) LinkAccount() (AccountLinkCommand, bool)
LinkAccount returns an independent typed adapter copy for this variant only.
func (Command) MarshalJSON ¶
MarshalJSON rejects implicit command persistence or accidental HTTP exposure.
func (Command) OneTimeCode ¶
func (c Command) OneTimeCode() (authentication.OneTimeCode, bool)
OneTimeCode borrows opaque code custody only for trusted fingerprinting and counted primary verification. False and zero code are returned for ordinary, zero, kernel and mixed commands. It does not verify, consume or grant a proof. Returned copies remain immutable; discard them after use. No secret bytes, persisted digest or conversion accessor is exposed. No IO or state changes.
func (Command) PasswordChangeCustody ¶
func (c Command) PasswordChangeCustody() (string, authentication.BearerCredential, authentication.ReauthenticationProof, bool)
PasswordChangeCustody borrows the original hash, opaque source bearer and upstream proof together for trusted native fingerprinting and validation. Zero, mixed and other variants return empty values and false. Returned proof is a caller-owned value: assignment cannot change retained custody. Never serialize/log these values or put them in the journal or public responses. Borrowing grants no signed provenance, freshness, consumption or transaction authority. Immutable concurrent reads are safe; discard copies after use.
func (Command) PasswordChangeFeature ¶
func (c Command) PasswordChangeFeature() (FeatureCommandSpec, bool)
PasswordChangeFeature returns owned hash/bearer/proof-free command metadata only for the authenticated password-change custody variant. Zero, mixed and every other variant return false. Mutating a projection cannot alter intent. This does not grant execution or authority; the native executor must also select and exhaustively bind PasswordChangeCustody. No IO or callbacks run.
func (Command) PasswordHash ¶
PasswordHash explicitly borrows the original encoded verifier for bounded native fingerprinting, primitive parsing and driver persistence. Zero, ordinary, kernel, unsupported and mixed commands return empty/false. Never log, serialize, persist in the kernel journal or expose the borrowed string in a response; hash storage belongs only to the password adapter. This grants no password verification, proof, current authority or transaction ownership. Immutable concurrent reads are safe; discard borrowed strings after use.
func (Command) PasswordHashFeature ¶
func (c Command) PasswordHashFeature() (FeatureCommandSpec, bool)
PasswordHashFeature returns owned hash-free metadata only for the explicit password-hash variant. Zero, ordinary, kernel, unsupported and mixed commands deny. Projection mutation cannot change retained intent. No IO or callback runs. This accessor does not admit execution, validate hash policy or prove authorization. Native mapping must also bind the separately borrowed hash.
func (Command) PasswordResetCustody ¶
func (c Command) PasswordResetCustody() (string, capability.Proof, bool)
PasswordResetCustody borrows the exact replacement verifier and original upstream proof together for bounded native fingerprinting and validation. Presence is structural, not current proof validity: aliases share terminal Transfer and the native owner must fail closed when verification denies. Zero, mixed and other variants return zero values and false. Never serialize, log or persist this pair in a command journal, recovery record or response. Verifier storage belongs only to the password adapter; immutable Go strings cannot be completely erased. No IO, transfer or consumption occurs here.
func (Command) PasswordResetFeature ¶
func (c Command) PasswordResetFeature() (FeatureCommandSpec, bool)
PasswordResetFeature returns an independently owned verifier/proof-free projection only for reset custody. Zero, mixed and other variants deny. Metadata survives proof transfer but grants no execution/recovery authority. Mutation of returned fields cannot change retained intent. No IO runs.
func (Command) PasswordResetInputCustody ¶
PasswordResetInputCustody borrows the original Secret and proof together. Copies retain shared terminal owner lifetimes; recheck on every bounded use. Never serialize, log or persist this pair. Presence is not authentication or permission to hash, reserve or consume. Zero and other variants deny.
func (Command) PasswordResetInputFeature ¶
func (c Command) PasswordResetInputFeature() (FeatureCommandSpec, bool)
PasswordResetInputFeature returns independently owned secret-free metadata for original reset preparation only. Zero, mixed and generated variants deny. Metadata survives owner destruction/transfer but grants no authority.
func (Command) PasswordSigninCustody ¶
func (c Command) PasswordSigninCustody() (primitive.Secret, authentication.BearerCredential, bool)
PasswordSigninCustody lends the original primitive Secret and pre-auth bearer together to native fingerprinting/comparison. Zero, mixed and other variants return zero values and false. Secret copies share terminal destruction and concurrency rules; the borrower must check/use its live owner, never interpret true as successful password comparison. Never log, persist or serialize the borrowed bearer, password bytes or this command. No IO or callbacks run.
func (Command) PasswordSigninFeature ¶
func (c Command) PasswordSigninFeature() (FeatureCommandSpec, bool)
PasswordSigninFeature returns an owned secret-free projection for the native password owner. Zero, mixed and other variants return false. Destruction of the password owner leaves metadata intact but grants no right to execute. Mutating returned fields cannot alter retained intent. No IO runs.
func (Command) PasswordSignupCustody ¶
func (c Command) PasswordSignupCustody() (string, authentication.BearerCredential, bool)
PasswordSignupCustody borrows both original prepared hash and pre-auth bearer together for bounded native fingerprinting and owner validation. Zero, mixed and other variants return empty/false. Never serialize, log or retain these values in a kernel journal or public response. Hash storage is password-owned; recovery uses secret-free correlation, not this command. Borrowing provides no HIBP provenance, cookie possession, flow consumption or current authority.
func (Command) PasswordSignupFeature ¶
func (c Command) PasswordSignupFeature() (FeatureCommandSpec, bool)
PasswordSignupFeature returns a separately owned secret-free metadata projection only for native signup custody. Zero, ordinary, mixed and other variants deny. Projection mutation cannot alter retained input. Success grants no execution, authentication or preparation authority. No IO runs.
func (Command) PasswordSignupInputCustody ¶
func (c Command) PasswordSignupInputCustody() (primitive.Secret, authentication.BearerCredential, bool)
PasswordSignupInputCustody lends the original Secret and pre-auth bearer together for bounded native intent binding and preparation. Secret copies share terminal destruction and primitive concurrency rules. Success is not a liveness lease or password/flow verification: check the live owner when borrowing bytes. Never serialize, log or persist this custody. Zero, mixed and other variants return zero values and false. No IO or callbacks run.
func (Command) PasswordSignupInputFeature ¶
func (c Command) PasswordSignupInputFeature() (FeatureCommandSpec, bool)
PasswordSignupInputFeature returns a separately owned secret-free original signup projection. Mutation cannot change retained intent. Zero, mixed and other variants deny. Metadata survives Secret destruction but grants no execution or recovery authority. No IO or callbacks run.
func (Command) PhonePasswordResetCustody ¶
func (c Command) PhonePasswordResetCustody() (string, capability.Proof, auth.OneTimeCode, auth.OneTimeCode, bool)
PhonePasswordResetCustody borrows the replacement verifier, canonical reset proof, phone OTP and independent TOTP together, in that order. It authenticates nothing and grants no transaction authority. Proof aliases share terminal transfer; Go cannot erase immutable verifier/code strings completely. Discard all secret-bearing copies after bounded use and keep only code-free recovery.
func (Command) PhonePasswordResetFeature ¶
func (c Command) PhonePasswordResetFeature() (FeatureCommandSpec, bool)
PhonePasswordResetFeature returns independently owned secret-free metadata only for the generated joint phone recovery command. Input/legacy/mixed/zero variants deny. Returned values are trusted adapter input, not public output.
func (Command) PhonePasswordResetInputCustody ¶
func (c Command) PhonePasswordResetInputCustody() (primitive.Secret, capability.Proof, auth.OneTimeCode, auth.OneTimeCode, bool)
PhonePasswordResetInputCustody borrows the original password, canonical reset proof, phone OTP and independent TOTP together, in that order. Presence is structural only; recheck all owner lifetimes and native authority during use. Never log, serialize or persist this tuple. Zero/mixed/other variants deny.
func (Command) PhonePasswordResetInputFeature ¶
func (c Command) PhonePasswordResetInputFeature() (FeatureCommandSpec, bool)
PhonePasswordResetInputFeature returns an independently owned secret-free projection only for original joint phone recovery preparation. Zero, mixed, generated and legacy commands deny. Metadata survives terminal owner use but never conveys authority or permission to generate a replacement verifier.
func (Command) PhonePasswordResetPreAuthCookie ¶
func (c Command) PhonePasswordResetPreAuthCookie() (auth.BearerCredential, bool)
PhonePasswordResetPreAuthCookie borrows only the exact original browser cookie retained by BindPhonePasswordResetPreAuth. Input and generated joint commands retain their distinct variants; generic Feature, PreAuthCookie and OneTimeCode remain closed rather than dropping a required factor. This is not proof of possession or current flow admission. Never log, serialize or persist Token; discard every borrowed secret-bearing copy after bounded native use. Zero, unbound, legacy and mixed commands return zero/false. No IO or callbacks run.
func (Command) PreAuthCookie ¶
func (c Command) PreAuthCookie() (authentication.BearerCredential, bool)
PreAuthCookie lends the exact submitted bearer only to trusted native owners for independently derived flow-cookie comparison. It never returns a caller digest or grants authentication/one-use authority. Code-free issuance custody and code-bearing submissions share this borrow; neither fabricates the other. Zero, ordinary, code-only and mixed commands return zero/false. Feature projections contain neither bearer nor code, and cannot reconstruct them. Discard borrowed copies after use; never log, serialize, persist or disclose Token. No IO or callbacks run.
func (Command) PrivacyExportProof ¶
func (c Command) PrivacyExportProof() (capability.Proof, bool)
PrivacyExportProof returns request-memory custody attached only by the configured service. Presence is not authority: the durable owner must reverify and reserve/consume atomically. Copies share the original one-transfer lifetime. Neither this accessor nor service admission consumes/transfers bearer material; never persist it. The metadata constructor attaches no original proof.
func (Command) RecoveryCode ¶
func (c Command) RecoveryCode() (authentication.RecoveryCode, bool)
RecoveryCode lends the exact opaque submitted recovery input to its trusted native fingerprint/comparison owner. It does not verify, consume or disclose a plaintext code. Zero, ordinary, OTP and mixed commands return zero/false. Copies remain immutable; discard after bounded use and never persist them.
func (Command) RequestPrivacyExport ¶
func (c Command) RequestPrivacyExport() (PrivacyExportRequestCommand, bool)
RequestPrivacyExport returns an owned projection copy only for this variant. Contents are sensitive trusted-adapter input, never public diagnostics.
func (Command) SessionToken ¶
func (c Command) SessionToken() (authentication.BearerCredential, bool)
SessionToken lends the exact submitted session bearer to trusted native owners for code-free issuance or code-bearing submissions without fabricating the other. It returns zero/false for zero, ordinary, code-only, pre-auth or mixed commands. A scalar projection cannot reconstruct this custody. Possession, current activity and authorization must be checked independently; this method grants none. Discard borrowed copies after bounded use, never log, persist or serialize Token. No code or bearer enters Feature projections or recovery.
func (Command) UnlinkAccount ¶
func (c Command) UnlinkAccount() (AccountUnlinkCommand, bool)
UnlinkAccount returns an immutable adapter value copy for this variant only.
func (Command) UpdateProfile ¶
func (c Command) UpdateProfile() (ProfileUpdateCommand, bool)
UpdateProfile returns a private adapter copy, never another command variant.
func (Command) UpdateUser ¶
func (c Command) UpdateUser() (UpdateUserCommand, bool)
UpdateUser returns a private copy, or false for another/invalid command kind.
func (Command) UserStatus ¶
func (c Command) UserStatus() (UserStatusCommand, bool)
UserStatus returns a value copy, or false for another/invalid command variant.
type CommandBinding ¶
type CommandBinding struct {
CommandID CommandID
TenantID TenantID
UserID UserID
// AnonymousFlowID is used only by an explicitly anonymous-targeted feature
// schema, mutually exclusive with UserID. It is a canonical flow identity,
// not an authenticated actor, user, command ID or continuation credential.
// Kernel commands forbid it; durable adapters must explicitly support it.
AnonymousFlowID string `json:",omitempty"`
ActorID ActorID
ActorKind authorization.SubjectKind
OperationID string
PolicyID string
PolicyVersion uint64
SchemaID string
SchemaVersion uint32
CorrelationID string
// RecordID is the exact account/identifier target for kernel record commands,
// including every noncommitted receipt; other kernel operations omit it.
// Feature bindings follow their FeatureOperation.RecordRequirement instead.
RecordID string
// LinkMode is required only for account-link commands, for every outcome.
LinkMode AccountLinkMode
}
CommandBinding is an immutable logical command scope, not an authority proof. Positive policy/schema versions and canonical safe IDs are mandatory. Actor kind is the exact upstream kind, not a caller role or administrator flag. CorrelationID is safe correlation only; it grants no continuation authority.
func (CommandBinding) ValidateFor ¶
func (b CommandBinding) ValidateFor(d FeatureOperation) error
ValidateFor checks every common scope field against one exact feature schema. It preserves canonical command identity, safe directory IDs, actual upstream actor kinds and positive policy versions. Required targets cannot be omitted; record-free operations cannot carry one. LinkMode must be zero. Descriptor ownership and policy must come from trusted composition, not this input. This is structural validation, not authentication, authorization, current authority, registration, a fingerprint or a transaction. Existing kernel Kernel Command constructors and kernel receipts remain separate closed variants. Feature receipts require their explicit Feature branch. Zero is invalid; invalid input returns redacted InvalidInputError. No I/O or callbacks run.
Example ¶
package main
import (
"fmt"
"github.com/faustbrian/go-authorization/v3"
identity "github.com/faustbrian/go-identity"
)
func main() {
// Compile-time composition descriptor, not an operation supplied by a client.
operation := identity.FeatureOperation{
Owner: "identity/session", OperationID: "identity.session.issue",
SchemaID: "session-issue", SchemaVersion: 1,
RecordRequirement: identity.FeatureRecordRequired,
}
binding := identity.CommandBinding{
CommandID: "AQEBAQEBAQEBAQEBAQEBAQ", TenantID: "tenant-a", UserID: "user-a",
ActorID: "actor-a", ActorKind: authorization.SubjectUser,
OperationID: "identity.session.issue", RecordID: "session-a",
PolicyID: "session-policy", PolicyVersion: 1,
SchemaID: "session-issue", SchemaVersion: 1, CorrelationID: "correlation-a",
}
fmt.Println(binding.ValidateFor(operation) == nil)
binding.SchemaVersion++
fmt.Println(binding.ValidateFor(operation) != nil)
}
Output: true true
type CommandID ¶
type CommandID string
CommandID is a canonical nonzero random 128-bit command identity. It is not derived from user data; preserve it across retries, including unknown outcomes. Possession grants no identity or database authority. Empty is invalid.
func NewCommandID ¶
NewCommandID reads exactly 16 crypto/rand bytes and rejects all-zero entropy.
func ParseCommandID ¶
ParseCommandID reconstructs only the canonical 22-byte unpadded base64url form.
type CommandResult ¶
type CommandResult struct {
Binding CommandBinding
Outcome CommitOutcome
User User
AuditEventID string
RetryAfter time.Duration
// ExpectedVersion is present only on a committed update receipt; the
// immutable result must be exactly one greater. Creation keeps it zero.
ExpectedVersion uint64
// Profile exists only for a committed self-service profile command. Adapters
// retain immutable copies; callers must never mutate a receipt concurrently.
Profile *UserProfile
// Revocation is present only on a committed status admission. It records
// pending cleanup, never fabricated asynchronous completion.
Revocation *RevocationOutcome
// Unlink is present only for a committed account unlink, never external
// provider completion. Treat retained receipts as immutable snapshots.
Unlink *AccountUnlinkReceipt
// Link is present only for committed identity-owned account link admission.
Link *AccountLinkReceipt
// Identifier is present only on a committed identifier mutation.
Identifier *IdentifierReceipt
// Feature is the exclusive structural feature receipt branch. Nil is omitted
// from JSON to preserve every historical kernel receipt byte. It never carries
// credentials or feature-native response payloads. Treat it as immutable.
Feature *FeatureReceipt `json:",omitempty"`
// PrivacyExport is exclusive committed queued snapshot admission metadata.
// Nil omission preserves historical receipt bytes. It is not a ready export
// or current authority; verify retained intent and the recorded evidence key.
PrivacyExport *PrivacyExportRequestReceipt `json:",omitempty"`
// Cascade is the committed feature owner's pending lifecycle admission.
// Nil omission preserves historical receipts. It is not consumer completion.
Cascade *LifecycleCascadeAdmission `json:",omitempty"`
}
CommandResult is the adapter's authoritative redacted receipt, not current user authority. A committed creation returns its immutable initial version-1 user and stable audit event ID. Other outcomes carry neither user nor audit ID. InProgress carries a positive retry delay up to one minute; all others zero.
func (CommandResult) Validate ¶
func (r CommandResult) Validate() error
Validate checks the closed receipt shape, immutable operation binding, version relationships and outcome-specific payload without authorization or current-state I/O. It returns a redacted InvalidInputError for invalid values. The zero value is invalid. Callers must not mutate a receipt concurrently.
func (CommandResult) ValidatePrivacyExportRequest ¶
func (r CommandResult) ValidatePrivacyExportRequest(c PrivacyExportRequestCommand, key PrivacyExportEvidenceKey) (PrivacyExportSnapshotV1, error)
ValidatePrivacyExportRequest checks an exact receipt against retained request intent and, for committed admission, verifies the complete snapshot with its recorded evidence key. It returns an immutable copied snapshot only on a structurally committed queued admission. Known noncommitted outcomes return zero snapshot and nil error without requiring an unused evidence key. Invalid values return redacted InvalidInputError. The request need not carry a live Grant: recovery must match the original intent even after proof expiry. This does not prove a commit, authorization, fresh session, primary reads or captured cuts; the platform-owned service/adapter must establish those facts. No IO, proof consumption or job transition occurs. Do not mutate arguments concurrently. The returned snapshot cannot be changed through receipt aliases.
type CommitOutcome ¶
type CommitOutcome uint8
CommitOutcome is the sole closed durable-command observation. Cancellation, panic, transport failure or a lease timeout is not evidence of rollback.
const ( CommitOutcomeInvalid CommitOutcome = iota CommitOutcomeNotCommitted CommitOutcomeCommitted CommitOutcomeUnknown CommitOutcomeConflict CommitOutcomeInProgress )
type ConflictError ¶
type ConflictError struct{ CommandID CommandID }
ConflictError is a stable non-enumerating command, version or uniqueness denial.
func (ConflictError) Error ¶
func (ConflictError) Error() string
type CreateUserCommand ¶
type CreateUserCommand struct {
Binding CommandBinding
Status Status
Attributes []AttributeUpdate
}
CreateUserCommand contains one prepared initial creation. Initial status is active; other lifecycle states require their own versioned lifecycle command. Attributes are not authority and must never contain credentials. Configure or construct values without concurrent mutation; Command freezes a deep copy.
type CredentialAuthorityQuery ¶
type CredentialAuthorityQuery struct {
TenantID TenantID
UserID UserID
CredentialID CredentialID
}
CredentialAuthorityQuery selects exactly one credential reference under its tenant and user. It contains no secret or proof and grants no lookup access.
func (CredentialAuthorityQuery) Validate ¶
func (q CredentialAuthorityQuery) Validate() error
Validate checks exact bounded IDs without normalization or ownership claims.
type CredentialAuthorityRecord ¶
type CredentialAuthorityRecord struct {
User User
AuthorityVersion uint64
Credential CredentialRef
Enabled bool
ExpiresAt time.Time
}
CredentialAuthorityRecord is one consistent primary observation. User.Version is aggregate CAS; AuthorityVersion is the separate tenant/user credential epoch; Credential.Version belongs to the exact credential record. No two of these counters substitute for one another. Enabled describes only the owned reference's eligibility, not secret verification, factor/provider eligibility or authorization. ExpiresAt zero is indefinite; nonzero expiry is exclusive and must be a UTC-representable microsecond instant in years 1..9999.
The record is data, not an opaque proof or validity lease. Its construction, copying and checking cannot establish read provenance or renew freshness. Treat it as immutable during a call; it contains no verifier or bearer.
type CredentialAuthorityRepository ¶
type CredentialAuthorityRepository interface {
GetCredentialAuthority(context.Context, CredentialAuthorityQuery) (CredentialAuthorityRecord, error)
}
CredentialAuthorityRepository is the platform-owned, concurrency-safe primary port. Reads honor a bounded context and return the user, credential epoch and reference from one consistent snapshot. Missing exact user or reference is ErrUserAbsent; corrupt/unavailable storage is redacted Unavailable. No partial positive result, fallback cache, default version or caller-supplied store may establish authority. Mutations and proof consumption belong to their owned command; this interface exposes no transaction or verification material.
type CredentialID ¶
type CredentialID string
CredentialID names a non-secret credential reference. Empty is invalid and structural bounds are the same as directory IDs; it is never a bearer.
type CredentialKind ¶
type CredentialKind uint8
CredentialKind is the closed credential namespace, not a login permission.
const ( CredentialPassword CredentialKind = iota + 1 CredentialPasskey CredentialProvider CredentialAPIKey )
type CredentialRef ¶
type CredentialRef struct {
ID CredentialID
TenantID TenantID
UserID UserID
Kind CredentialKind
Owner string
Version uint64
}
CredentialRef is a versioned non-secret pointer to one owning feature. It contains no verifier, bearer, factor material or provider payload. Ownership and authoritative usability are separate from this structural reference.
func (CredentialRef) Format ¶
func (CredentialRef) Format(state fmt.State, verb rune)
Format keeps references out of diagnostic snapshots despite carrying no secret.
func (CredentialRef) Validate ¶
func (c CredentialRef) Validate(tenant TenantID, user UserID) error
Validate checks a reference's exact user and closed kind/owner pairing. Password/API-key owners are their identity features, passkey owners may be webauthn or passkey, and federation/provider owners may be sso or identity/oauth. Neither its tenant/user fields nor ID grants authority.
type Cursor ¶
type Cursor struct {
// contains filtered or unexported fields
}
Cursor is an immutable storage-neutral snapshot position, not authority. Its zero value starts a new snapshot. Only trusted repositories construct continuations; wire cursors are authenticated and decoded by the service.
func NewCursor ¶
NewCursor constructs a repository continuation for a canonical random snapshot ID and a positive position no greater than MaxInt64. Adapters must never substitute a user's ID for the snapshot ID or recreate expired snapshots.
Example ¶
package main
import (
"fmt"
"github.com/faustbrian/go-identity"
)
func main() {
// A trusted repository records the scanned position in its retained snapshot.
// The service authenticates/encrypts this value for wire continuation; it is
// not a tenant permission, user identity or credential.
cursor, err := identity.NewCursor("AQEBAQEBAQEBAQEBAQEBAQ", 10)
if err != nil {
panic(err)
}
fmt.Println(cursor.Position())
}
Output: 10
func (Cursor) SnapshotID ¶
SnapshotID returns the opaque repository snapshot identifier, not a user ID.
type DeadlineExceededError ¶
type DeadlineExceededError struct{}
DeadlineExceededError identifies expiration of the bounded read context.
func (DeadlineExceededError) Error ¶
func (DeadlineExceededError) Error() string
func (DeadlineExceededError) Unwrap ¶
func (DeadlineExceededError) Unwrap() error
type DecideRetentionFunc ¶
type DecideRetentionFunc func(context.Context, RetentionPolicyInput) (RetentionPolicyDecision, error)
DecideRetentionFunc is a concurrent-safe bounded pure retention callback.
type DeliverySecurityEventInput ¶
type DeliverySecurityEventInput struct {
Transition DeliverySecurityTransition
OccurredAt time.Time
TenantID TenantID
IntentID string
CommandID CommandID
WorkerActorID, CorrelationID string
PolicyID string
PolicyVersion, ProviderVersion uint64
BeforeVersion, AfterVersion uint64
}
DeliverySecurityEventInput is trusted owned-adapter attribution. IDs are stable internal tokens, not usernames, addresses or credentials. IntentID is the exact nonzero 64-byte lowercase hexadecimal effect ID. WorkerActorID is the authenticated service account, not a lease name or the message owner. Versions are the database-owned status versions before/after this transition. CommandID and causation preserve the original owning command. No fields carry recipient, rendering, provider reference, raw receipt, or arbitrary claims.
type DeliverySecurityTransition ¶
type DeliverySecurityTransition uint8
DeliverySecurityTransition classifies committed local delivery bookkeeping, not a provider invocation or an unknown database commit. Zero is invalid.
const ( DeliverySecurityAttempt DeliverySecurityTransition = iota + 1 // Committed invocation lease, before provider IO. DeliverySecurityAccepted // Provider acceptance, not delivery. DeliverySecurityConfirmed // Authoritative delivery success. DeliverySecurityRejected // Permanent rejection or bounce. DeliverySecurityRetry // Authoritative transient no-success evidence. DeliverySecurityUnknown // Observed ambiguous provider outcome. DeliverySecurityCancelled // Local stop, not remote confirmation. DeliverySecurityExpired // Unsent work expired and custody erased. DeliverySecurityExhausted // Retry policy exhausted, not provider rejection. DeliverySecurityReleased // Lease released with authoritative no-invocation evidence. DeliverySecurityPayloadErased // Expired custody erased without inventing an outcome. DeliverySecurityLeaseLost // Lease expired without an observed provider result. )
type FeatureCommandSpec ¶
type FeatureCommandSpec struct {
Binding CommandBinding
Operation FeatureOperation
Fields []FeatureField
}
FeatureCommandSpec is a structural, storage-neutral trusted mapping input. Binding must match Operation exactly. Fields contains 0..128 distinct named scalars and at most 256 KiB counted as each name's byte length, one kind byte and value bytes (integers/time count eight, booleans one). There are no floats, executable callbacks, raw JSON/CBOR, transaction handles or arbitrary values. This public projection is not a secret-custody boundary: never log/serialize it or use it for HTTP responses. The returned opaque Command supplies the diagnostic boundary. Do not mutate inputs concurrently with construction. Feature services still own their native typed commands. Trusted adapters alone map these to this shared vocabulary; applications need no workflow glue.
type FeatureField ¶
type FeatureField struct {
Name string
Value FeatureValue
}
FeatureField is one named typed input, not an extension hook or arbitrary serialized blob. Name is at most 128 lowercase ASCII bytes in dot-separated segments with the FeatureOperation.OperationID syntax. Duplicate names deny. Named field order has no meaning; owners explicitly encode sequence indexes in field names when their schema needs ordered inputs. All behavior-affecting input, including expected versions and options, must be mapped exhaustively.
type FeatureKind ¶
type FeatureKind uint8
FeatureKind selects exactly one named command scalar. Zero/unknown kinds are invalid; inactive members must be exactly zero (including nil Bytes).
const ( // FeatureText selects bounded UTF-8 text without implicit normalization. FeatureText FeatureKind = iota + 1 // FeatureBytes selects bounded binary metadata, never a raw bearer/secret. FeatureBytes // FeatureUint64 preserves the complete unsigned authority-version range. FeatureUint64 // FeatureInt64 selects a signed integer (including duration microseconds). FeatureInt64 // FeatureBool selects an explicit boolean, including false. FeatureBool // FeatureTime selects a nonzero microsecond-exact year 1..9999 UTC instant. FeatureTime )
type FeatureOperation ¶
type FeatureOperation struct {
Owner string
OperationID string
SchemaID string
SchemaVersion uint32
RecordRequirement FeatureRecordRequirement
// SubjectRequirement is frozen schema policy, not selected by request data.
// Zero retains the original user-only contract and serialized shape.
SubjectRequirement FeatureSubjectRequirement `json:",omitempty"`
}
FeatureOperation identifies one storage-neutral feature-owned operation. Trusted composition supplies a compile-time descriptor, never request data. Owner is a canonical lowercase slash-separated module label; OperationID is a lowercase dot-separated operation name (each segment starts with a letter, ends with a letter/digit and otherwise allows letters, digits and hyphens). Both are bounded to 128 bytes. SchemaID follows existing safe directory-ID rules; SchemaVersion is positive. The record requirement is explicit. Descriptors are scalar values: freeze them at composition and do not mutate one concurrently with validation. Validation performs no I/O, registration, authorization or command execution. Kernel-owned operations are excluded.
func (FeatureOperation) Validate ¶
func (d FeatureOperation) Validate() error
Validate checks structural descriptor identity, not ownership authenticity. The owning feature adapter must validate its full typed command and selected policy; the coordinator must match the exact immutable registered descriptor before admission. Names alone never enable an execution phase. Invalid input returns a redacted InvalidInputError; zero is invalid.
type FeatureReceipt ¶
type FeatureReceipt struct {
Operation FeatureOperation
BeforeVersion uint64
AfterVersion uint64
}
FeatureReceipt is a storage-neutral safe primary-record receipt, never a feature-native response or authentication proof. Operation retains the exact trusted descriptor on every outcome. A committed record-target operation has AfterVersion == BeforeVersion+1 without overflow; creation starts at 0 -> 1. Record-free operations and every noncommitted outcome keep both versions zero. The target ID is CommandResult.Binding.RecordID, not an alternate locator. Feature owners validate their native result and complete command schema; this shared vocabulary carries no arbitrary payload, bearer or secret. Public fields permit trusted durable reconstruction; zero is invalid through CommandResult.Validate. Callers must not mutate a receipt concurrently. Structural validation does not confirm a commit, grant current authority or enable coordinator execution; only the owning durable outcome establishes it.
Example ¶
package main
import (
"fmt"
"github.com/faustbrian/go-authorization/v3"
identity "github.com/faustbrian/go-identity"
)
func main() {
// A structural trusted-adapter projection, not issuance or commit evidence.
r := identity.CommandResult{
Binding: identity.CommandBinding{CommandID: "AQEBAQEBAQEBAQEBAQEBAQ", TenantID: "tenant-a", UserID: "user-a", ActorID: "actor-a", ActorKind: authorization.SubjectUser, OperationID: "identity.session.issue", RecordID: "session-a", PolicyID: "session-policy", PolicyVersion: 1, SchemaID: "session-issue", SchemaVersion: 1, CorrelationID: "correlation-a"},
Outcome: identity.CommitOutcomeCommitted, AuditEventID: "audit-a",
Feature: &identity.FeatureReceipt{Operation: identity.FeatureOperation{Owner: "identity/session", OperationID: "identity.session.issue", SchemaID: "session-issue", SchemaVersion: 1, RecordRequirement: identity.FeatureRecordRequired}, AfterVersion: 1},
}
if r.Validate() != nil {
panic("invalid example receipt")
}
fmt.Println(r.Feature.BeforeVersion, r.Feature.AfterVersion)
}
Output: 0 1
type FeatureRecordRequirement ¶
type FeatureRecordRequirement uint8
FeatureRecordRequirement fixes whether an operation has one exact record target. It is a schema decision, not inferred from submitted input. Zero and unknown values are invalid; feature operations never borrow account LinkMode.
const ( // FeatureRecordOmitted requires an empty CommandBinding.RecordID. FeatureRecordOmitted FeatureRecordRequirement = iota + 1 // FeatureRecordRequired requires a valid exact CommandBinding.RecordID. FeatureRecordRequired )
type FeatureSubjectRequirement ¶
type FeatureSubjectRequirement uint8
FeatureSubjectRequirement fixes an operation's target identity namespace at trusted composition. The default preserves existing user-targeted schemas. Anonymous-flow targeting is explicit and never substitutes a flow for UserID. This does not authenticate a flow or grant execution/recovery authority.
const ( // FeatureSubjectUser requires UserID and forbids AnonymousFlowID. FeatureSubjectUser FeatureSubjectRequirement = iota // FeatureSubjectAnonymousFlow requires AnonymousFlowID and an empty UserID. // The actor remains a separately verified user, API key or service account. FeatureSubjectAnonymousFlow )
type FeatureValue ¶
type FeatureValue struct {
Kind FeatureKind
Text string
Bytes []byte
Uint64 uint64
Int64 int64
Bool bool
Time time.Time
}
FeatureValue is a closed scalar union for trusted feature command mapping. Kind is required even for empty text/bytes, false or zero integers. Text/Bytes are at most 8192 bytes; text must be valid UTF-8. Time is normalized to UTC without changing its instant. Values are command input, not authentication or an authority proof. Never place raw passwords, session/API-key bearers, private keys or provider tokens here. Feature owners define and validate exact field semantics, including confidentiality and cryptographic evidence provenance.
type FieldAuthorization ¶
type FieldAuthorization string
FieldAuthorization is a required write class passed to the upstream policy service. Administrator/system strings never grant a caller either role.
const ( FieldWriteSelf FieldAuthorization = "self" FieldWriteAdministrator FieldAuthorization = "administrator" FieldWriteSystem FieldAuthorization = "system" )
type FieldName ¶
type FieldName struct{ Value string }
FieldName is a canonical schema field name, never an attribute value.
type FieldPermission ¶
type FieldPermission string
FieldPermission is an explicit input or output permission, not authorization.
const ( FieldDenied FieldPermission = "denied" FieldRead FieldPermission = "read" FieldWrite FieldPermission = "write" FieldReadWrite FieldPermission = "read-write" )
type FieldPolicy ¶
type FieldPolicy struct {
Name string
Kind AttributeKind
Cardinality Cardinality
Default AttributeValue
Normalization NormalizationPolicy
InputPermission FieldPermission
OutputPermission FieldPermission
WriteAuthorization FieldAuthorization
Sensitivity Sensitivity
Indexed bool
MigrationVersion uint32
}
FieldPolicy defines one immutable additional field. Names use lower ASCII letters, digits and underscores, start with a letter and are 1..128 bytes. Core id/tenant_id/status/version names are reserved. Defaults must match kind and cardinality. Indexed=false is valid. MigrationVersion must equal the schema Version; incompatible versions require an explicit new schema.
type FinalAccessError ¶
type FinalAccessError struct{}
FinalAccessError means unlink would leave no independent human login method. Public workflows must authorize before running this enumeration-sensitive check.
func (FinalAccessError) Error ¶
func (FinalAccessError) Error() string
type ForbiddenError ¶
type ForbiddenError struct{}
ForbiddenError is a redacted policy denial or enumeration-safe absence.
func (ForbiddenError) Error ¶
func (ForbiddenError) Error() string
type GetUserQuery ¶
GetUserQuery is an exact tenant/user lookup with a bounded safe projection. Repository implementations must not return another subject or tenant.
type Hook ¶
type Hook interface {
Before(context.Context, BeforeHookInput) (BeforeHookResult, error)
After(context.Context, AfterHookInput) error
}
Hook supplies cooperative, bounded, concurrency-safe application callbacks. Before runs outside transactions and must not perform durable side effects: concurrent attempts may call it before the sole reservation selects a winner. After runs after transaction closure; its failure cannot undo committed work. Neither phase receives a store, transaction, proof or continuation authority. Use the durable outbox, not these callbacks, for retryable external effects.
type HookEnrichment ¶
type HookEnrichment struct{ Fields []HookField }
HookEnrichment replaces or adds registered writable metadata only. It never changes OperationContext or grants permission to modify protected authority.
type HookField ¶
type HookField struct {
Name string
Value AttributeScalar
Sensitivity Sensitivity
}
HookField is one registered bounded scalar. Credentials are forbidden even when marked secret. Diagnostic formatting deliberately hides every value.
type HookFieldRegistration ¶
type HookFieldRegistration struct {
Name string
Kind AttributeKind
Sensitivity Sensitivity
Enrichment bool
}
HookFieldRegistration fixes one scalar's kind/classification and whether before hooks may enrich it. Core reserved fields cannot be writable. Domain adapters must register only metadata safe for their selected workflow.
type HookObservation ¶
type HookObservation struct {
Outcome AttemptedCommitOutcome
Notes []PolicyReason
}
HookObservation is safe outcome metadata after transaction closure. Notes are registered codes, never user values, credentials or replay payloads. Notes must be non-nil; an explicit empty collection observes no extra notes.
type HookRunner ¶
type HookRunner struct {
// contains filtered or unexported fields
}
HookRunner runs1..64 callbacks in registration order, stopping at the first rejection/failure. One shared bounded budget covers the complete phase. Callback-context reentry into any HookRunner is rejected, including After. Dependencies are borrowed and must be concurrency-safe; the runner owns no lock, goroutine or resource lifetime. Zero/nil runners are invalid.
func NewHookRunner ¶
func NewHookRunner(hooks []Hook, config HookRunnerConfig) (*HookRunner, error)
NewHookRunner validates and copies ordered callbacks and field/reason policy. No callback, IO, transaction or provider runs during construction.
func (*HookRunner) After ¶
func (r *HookRunner) After(ctx context.Context, in AfterHookInput) error
After observes an already closed transaction and stops on the first error. Errors/panics are redacted, not translated to rollback. The workflow must conserve its original known result even if this returns an error. There is no automatic retry, exactly-once external-effect claim or replay observation.
func (*HookRunner) Before ¶
func (r *HookRunner) Before(ctx context.Context, in BeforeHookInput) (BeforeHookResult, error)
Before invokes ordered hooks with independent metadata copies. Enrichments must match registration and may write each field at most once across a phase; at most64 total fields/enrichments and32 registered reasons are retained. The returned data is not applied to domain records or authorization by this runner: that remains the selected adapter's explicit pretransaction policy.
type HookRunnerConfig ¶
type HookRunnerConfig struct {
Fields []HookFieldRegistration
Reasons []PolicyReason
MaximumDuration time.Duration
}
HookRunnerConfig is copied immutable composition: at most64 fields and32 unique reason codes, and a positive maximum duration no greater than1 minute. Secret fields and lists are unavailable. Hooks must honor context deadlines; execution is synchronous, with no goroutine attempting forced preemption.
type IdempotencyKey ¶
type IdempotencyKey struct {
// contains filtered or unexported fields
}
IdempotencyKey owns a transient immutable client retry key with no raw accessor. Zero is invalid; copies are comparable and safe for concurrent digesting. Equality identifies the same constructed owner, not equal bytes; independently constructed keys may be correlated only by scoped digests. Retain only keyed digests in durable mappings. Dropping references does not guarantee erasure of immutable strings or caller-owned copies.
func NewIdempotencyKey ¶
func NewIdempotencyKey(raw []byte) (IdempotencyKey, error)
NewIdempotencyKey copies exactly 1..256 ASCII HTTP token bytes: letters, digits and !#$%&'*+-.^_`|~. Spaces, commas, quotes, controls, non-ASCII bytes and separators deny. There is no trimming, case folding or normalization. InvalidInputError is redacted. HTTP adapters separately reject duplicate headers and keys supplied anywhere other than the single permitted header. This pure constructor performs no I/O or authentication.
Example ¶
package main
import (
"fmt"
identity "github.com/faustbrian/go-identity"
)
func main() {
// The HTTP adapter supplies exactly one validated Idempotency-Key header;
// direct API consumers construct the same opaque exact-byte value.
key, err := identity.NewIdempotencyKey([]byte("example_retry_key"))
if err != nil {
panic(err)
}
fmt.Println(key)
}
Output: identity.IdempotencyKey(redacted)
func (IdempotencyKey) Digest ¶
func (k IdempotencyKey) Digest(authorityKey [32]byte) ([32]byte, error)
Digest returns HMAC-SHA-256 under a nonzero authority-owned 32-byte lookup key over "golib.identity.request-key.v1\x00", unsigned 64-bit big-endian raw length and exact raw bytes. It conveys no authorization or command outcome. The consuming adapter owns tenant/actor/method/route scoping and immutable lookup-key namespace; rotating this key cannot silently reassign old retries. Zero client or authority keys return redacted InvalidInputError. No I/O runs.
func (IdempotencyKey) Format ¶
func (IdempotencyKey) Format(s fmt.State, _ rune)
Format never reveals raw client bytes for any diagnostic verb.
func (IdempotencyKey) LogValue ¶
func (IdempotencyKey) LogValue() slog.Value
LogValue emits a constant independent of client bytes or validity.
func (IdempotencyKey) MarshalJSON ¶
func (IdempotencyKey) MarshalJSON() ([]byte, error)
MarshalJSON rejects implicit key persistence or HTTP disclosure.
func (IdempotencyKey) MarshalText ¶
func (IdempotencyKey) MarshalText() ([]byte, error)
MarshalText rejects text and map-key serialization.
type Identifier ¶
type Identifier struct {
ID IdentifierID
UserID UserID
Kind IdentifierKind
CanonicalValue string
DisplayValue string
Verified bool
Primary bool
Version uint64
// NormalizationProfile and NormalizationVersion preserve the exact policy
// that produced CanonicalValue. Both absent denotes an existing unbound
// record, never permission to reinterpret it using today's policy.
// Omit absent bindings to preserve canonical JSON in existing authenticated
// signup-input envelopes; adding zero fields would make their byte check fail.
NormalizationProfile string `json:",omitempty"`
NormalizationVersion uint32 `json:",omitempty"`
}
Identifier is an identity-owned directory record. Tenant scope is inherited from its enclosing authoritative User partition, never inferred from UserID. Values must already be canonical under the selected versioned feature policy; structural validation does not normalize or prove uniqueness/verification. Primary is per kind and requires verification. Treat snapshots as immutable.
func (Identifier) Format ¶
func (Identifier) Format(s fmt.State, verb rune)
Format prevents canonical and display identifiers from entering diagnostics.
func (Identifier) Validate ¶
func (i Identifier) Validate(user UserID) error
Validate checks the exact user, closed kind, bounded values and positive record version. It confers no authority and does not accept a claimed primary without verification. Canonical/display text is at most 512 UTF-8 bytes with no C0/C1 controls; provider-subject spaces are preserved, not trimmed.
type IdentifierAccessPlan ¶
type IdentifierAccessPlan struct {
Mutation IdentifierMutation
RemainingUsablePaths uint16
}
IdentifierAccessPlan is a copied provisional mutation and bounded count of surviving usable human login paths, not distinct credentials. It grants no permission or durable outcome. A successful decision never consumes proof.
func CheckIdentifierAccess ¶
func CheckIdentifierAccess(snapshot IdentifierAccessSnapshot, change IdentifierChange, now time.Time) (IdentifierAccessPlan, error)
CheckIdentifierAccess computes the identifier transition and rejects any resulting loss of all human login paths. Call only after authorization, and repeat under durable owner locks with current credential/factor/provider eligibility and one trusted clock sample. Independent methods survive; identifier-bound methods need the same canonical value and required successor verification/primary state. Expiry is exclusive; API keys never count. Malformed/foreign/duplicate paths return InvalidInput, stale dependency versions return Conflict, and no surviving path returns FinalAccessError. Other transition errors retain ApplyIdentifierChange semantics. All errors return a zero plan; inputs are not mutated. No IO or authority refresh occurs. Pre-auth registration must use its distinct workflow, not this current-human access decision before a login method exists.
type IdentifierAccessSnapshot ¶
type IdentifierAccessSnapshot struct {
State IdentifierState
Accounts []Account
Methods []IdentifierLoginMethod
}
IdentifierAccessSnapshot is a complete consistent primary view for the pure final-access decision. Methods contains at most 128 distinct login paths; Accounts has AccountSnapshot semantics. The durable owner must establish current method eligibility and lock every applicable owner before constructing this view. It is neither an authority proof nor a reusable validity lease. Treat all input collections as immutable during a call.
type IdentifierAction ¶
type IdentifierAction uint8
IdentifierAction selects one pure domain transition, never authorization.
const ( IdentifierAttach IdentifierAction = iota + 1 IdentifierVerify IdentifierMakePrimary IdentifierReplace IdentifierRemove // IdentifierRestartVerification advances only an existing pending, // non-primary verification generation. Native resend must authorize fresh // proof and atomically replace delivery/capability custody; generic identifier // commands do not expose this feature-specific transition. IdentifierRestartVerification // IdentifierVerifyPrimary verifies one pending email and selects it as // primary in one native transition. The feature owner must prove original // new-address possession and current change policy; generic identifier // commands do not expose this compound action. IdentifierVerifyPrimary // IdentifierRename changes an already comparison-bound username only. A // display-only change preserves possession; a new canonical value retires // the predecessor and resets verification like replacement. Native username // admission must supply fresh proof and the old-name cooldown policy. IdentifierRename // IdentifierReplaceVerifiedPhone is a feature-only atomic replacement after // actual new-number OTP consumption. It preserves primary selection and // retires the original value while advancing each version exactly once. // Generic identifier commands do not expose this action; the native phone // owner must bind proof, current authority, OTP and all required effects. IdentifierReplaceVerifiedPhone )
type IdentifierChange ¶
type IdentifierChange struct {
TenantID TenantID
UserID UserID
Action IdentifierAction
ID IdentifierID
Kind IdentifierKind
CanonicalValue string
DisplayValue string
NormalizationProfile string `json:",omitempty"`
NormalizationVersion uint32 `json:",omitempty"`
ExpectedUserVersion uint64
ExpectedAuthorityVersion uint64
ExpectedIdentifierVersion uint64
ExpectedVerificationVersion uint64
}
IdentifierChange is bounded intent and exact optimistic fences. Attach, Replace, Rename and ReplaceVerifiedPhone supply Kind/CanonicalValue/DisplayValue; other actions omit them. Attach must omit target versions; other actions require both exact target versions. Replacement preserves ID/kind, resets verification and primary, and retires the old value. Rename requires the exact existing username comparison binding and preserves verification for display-only edits. Trusted feature owners establish canonicalization, proof and reuse policy; client input must never directly reach ApplyIdentifierChange.
type IdentifierChangeRequest ¶
type IdentifierChangeRequest struct {
CommandID CommandID
Change IdentifierChange
Proof capability.Proof
SessionID string
SessionVersion uint64
ActorScope authorization.DecisionContext
CorrelationID string
}
IdentifierChangeRequest is trusted current-human input, not public JSON. Preserve the exact command/proof/session/version and intent across retries. Canonical values come from the fixed, versioned owning feature policy, not client casing or the Go toolchain. Feature pre-auth flows remain separate.
type IdentifierCommand ¶
type IdentifierCommand struct {
Binding CommandBinding
Change IdentifierChange
Proof capability.Grant
SessionID string
SessionVersion uint64
}
IdentifierCommand is immutable intent for the sole durable identity owner. Verified proof comes from the configured identity signer only after real session, canonicalization and feature challenge/reuse checks. Construction grants no such authority. The owner repeats fresh policy, session, proof, uniqueness, cooldown and final-access checks under locks before consumption.
type IdentifierConfig ¶
type IdentifierConfig struct {
Query UserQueryConfig
ProofIssuer, ProofAudience string
MaximumProofAge time.Duration
}
IdentifierConfig freezes query policy and exact signed-proof authority. MaximumProofAge is positive and at most five minutes. It does not establish current credential-specific reauthentication or challenge verification.
type IdentifierID ¶
type IdentifierID string
IdentifierID is an exact case-sensitive record ID, separate from an email, phone, username or provider subject. Empty is invalid; at most 128 UTF-8 bytes are accepted. Imported canonical IDs are preserved unchanged.
func ParseIdentifierID ¶
func ParseIdentifierID(raw string) (IdentifierID, error)
ParseIdentifierID validates structure without granting ownership or authority.
type IdentifierKind ¶
type IdentifierKind string
IdentifierKind selects an exact indexed identifier namespace. Empty means no identifier filter, not a wildcard namespace for a supplied value.
const ( IdentifierEmail IdentifierKind = "email" IdentifierPhone IdentifierKind = "phone" IdentifierUsername IdentifierKind = "username" IdentifierProviderSubject IdentifierKind = "provider-subject" // IdentifierAnonymousPlaceholder is the reserved non-contact namespace owned // by anonymous identity lifecycle. It is never verified, primary, deliverable // or a generic identifier mutation target. Ordinary email lookup cannot match it. IdentifierAnonymousPlaceholder IdentifierKind = "anonymous-placeholder" )
func (IdentifierKind) Valid ¶
func (k IdentifierKind) Valid() bool
Valid recognizes a persisted identifier kind. Empty is only an omitted list filter, never a valid kind for an identifier record or mutation.
type IdentifierLoginMethod ¶
type IdentifierLoginMethod struct {
Method LoginMethod
IdentifierID IdentifierID
IdentifierVersion, VerificationVersion uint64
RequiresVerified, RequiresPrimary bool
}
IdentifierLoginMethod is one authority-owner-evaluated human login path. Method.Usable includes current credential, policy, factor and provider checks; a caller boolean is not authority. An optional identifier dependency names its exact current record and verification versions. Empty IdentifierID denotes an independent path and requires zero versions and false requirements. Different identifiers may provide alternative paths for the same exact credential. RequiresPrimary/RequiresVerified come from the selected login policy, never client input. Replacement never inherits access to the old canonical value.
type IdentifierMutation ¶
type IdentifierMutation struct {
State IdentifierState
Retired *Identifier
RetiredVerification *Verification
}
IdentifierMutation is privately copied proposed state, not a committed outcome. Retired and RetiredVerification are present only for replacement, canonical-changing rename or removal. Removal advances their versions and revokes verification; replacement/rename retain the original pair for old-value reuse tombstone creation. Display-only rename retires nothing. The adapter must derive a scoped keyed non-reversible reuse digest, never persist canonical values in plaintext tombstones/events/audit. Legal storage of current directory values remains a separate encrypted storage policy.
func ApplyIdentifierChange ¶
func ApplyIdentifierChange(state IdentifierState, change IdentifierChange, now time.Time) (IdentifierMutation, error)
ApplyIdentifierChange computes an all-or-nothing copied next state without I/O, goroutines, locks, proof verification, clock reads or input mutation. Active users only; overflow and stale versions deny. Each successful change advances user aggregate and identifier authority exactly once. Primary switching bumps both changed records without renewing verification time. Same-value replacement and repeated verify/primary are conflicts, not replay.
The platform durable owner must check exact same-command replay first, lock the full partition and tenant uniqueness index, validate current operation authorization/canonical policy, establish proof/version/session freshness, enforce final usable access and old-value cooldown/reuse policy, then consume applicable one-use proof/risk and persist state, tombstones, lifecycle events, audit and original receipt atomically. This function proves none of those durable/authority claims. Verify is usable only after the feature's real subject/value/version-bound challenge succeeds; a caller boolean is not proof. Errors return zero mutation. now is one trusted owner sample; newly persisted verification time is UTC truncated to microseconds, never a new proof lifetime.
Example ¶
package main
import (
"fmt"
"time"
identity "github.com/faustbrian/go-identity"
)
func main() {
// The platform owner supplies locked primary state. This pure computation
// does not authorize a caller, verify a challenge or commit durable state.
state := identity.IdentifierState{
User: identity.User{ID: "user", TenantID: "tenant", Status: identity.StatusActive, Version: 1},
AuthorityVersion: 1,
}
next, err := identity.ApplyIdentifierChange(state, identity.IdentifierChange{
TenantID: "tenant", UserID: "user", ID: "email-record",
Action: identity.IdentifierAttach, Kind: identity.IdentifierEmail,
CanonicalValue: "person@example.test", DisplayValue: "Person@example.test",
ExpectedUserVersion: 1, ExpectedAuthorityVersion: 1,
}, time.Date(2026, 10, 2, 8, 0, 0, 0, time.UTC))
if err != nil {
panic(err)
}
fmt.Println(next.State.AuthorityVersion, next.State.Identifiers[0].Verified, next.State.Identifiers[0].Primary)
}
Output: 2 false false
func ApplyIdentifierRemovalWithPrimary ¶
func ApplyIdentifierRemovalWithPrimary(state IdentifierState, change IdentifierChange, selection IdentifierPrimarySelection, now time.Time) (IdentifierMutation, error)
ApplyIdentifierRemovalWithPrimary copies one removal and explicit primary promotion into a single proposed transition. The removed record must be the current primary; its replacement must be a distinct, already-verified record of the same kind in the same partition with exact non-overflowing versions. User/authority advance once; promotion advances only the replacement record, never its verification version or time. Errors return zero and inputs remain untouched. No IO, clock sampling, authority, one-use or durable effect occurs. A native feature must bind the selection in its original intent, lock/recheck the complete partition and persist proof/session/audit/lifecycle effects with this mutation. IdentifierIntentDigest still binds only the base change.
type IdentifierPrimarySelection ¶
type IdentifierPrimarySelection struct {
ID IdentifierID
ExpectedIdentifierVersion uint64
ExpectedVerificationVersion uint64
}
IdentifierPrimarySelection names one exact existing verified record and its independent versions. Zero is not a selection. It grants no authority and cannot select a subject, change a value or renew verification freshness.
func (IdentifierPrimarySelection) Format ¶
func (IdentifierPrimarySelection) Format(s fmt.State, _ rune)
Format omits the selected identifier's personal correlation.
func (IdentifierPrimarySelection) Validate ¶
func (s IdentifierPrimarySelection) Validate() error
Validate checks bounded identifier and independent version syntax only. It performs no lookup or authorization; zero and overflowing versions deny.
type IdentifierProjection ¶
type IdentifierProjection struct {
// contains filtered or unexported fields
}
IdentifierProjection is an opaque, bounded snapshot, not authentication, ownership, permission, a commit receipt or authoritative freshness evidence. Its zero is invalid. NewIdentifierProjection is the only construction path; reconstructing it from caller-supplied metadata never proves a primary read. Copies support concurrent immutable reads and own no resources or goroutines. Value omission is permanent for that projection: no hidden mailbox is retained.
func NewIdentifierProjection ¶
func NewIdentifierProjection(s IdentifierProjectionSpec) (IdentifierProjection, error)
NewIdentifierProjection validates expected tenant/user/record, complete ordered partition consistency and the explicit output selection before copying one identifier. It preserves canonical/display text, imported IDs and all versions unchanged; it performs no normalization, policy callback, IO or transition. Primary requires verification; pending/revoked values are valid non-primary snapshots. InvalidInputError is redacted and returns an invalid zero value. The calling feature separately owns authorization, disclosure, primary read and commit-outcome checks. No timestamp here can substitute for those checks.
Example ¶
package main
import (
"fmt"
"time"
identity "github.com/faustbrian/go-identity"
)
func main() {
// A trusted feature has already authorized and read this consistent partition.
observed := time.Date(2026, 10, 10, 19, 0, 0, 0, time.UTC)
state := identity.IdentifierState{
User: identity.User{ID: "user-one", TenantID: "tenant-one", Status: identity.StatusActive, Version: 2},
AuthorityVersion: 2,
Identifiers: []identity.Identifier{{
ID: "email-one", UserID: "user-one", Kind: identity.IdentifierEmail,
CanonicalValue: "member@example.test", Verified: true, Version: 2,
}},
Verifications: []identity.Verification{{
IdentifierID: "email-one", State: identity.VerificationVerified,
VerifiedAt: observed.Add(-time.Minute), Version: 2,
}},
}
projection, err := identity.NewIdentifierProjection(identity.IdentifierProjectionSpec{
TenantID: "tenant-one", UserID: "user-one", IdentifierID: "email-one",
State: state, ObservedAt: observed, Values: identity.IdentifierValuesOmitted,
})
if err != nil {
panic(err)
}
metadata, err := projection.Bindings()
if err != nil {
panic(err)
}
_, _, hasValues := projection.Values()
fmt.Println(metadata.Verified, metadata.IdentifierVersion, hasValues)
}
Output: true 2 false
func (IdentifierProjection) Bindings ¶
func (p IdentifierProjection) Bindings() (IdentifierProjectionBindings, error)
Bindings returns an owned metadata copy or a redacted InvalidInputError for zero. It returns no address text and proves neither current access nor commit.
func (IdentifierProjection) Format ¶
func (IdentifierProjection) Format(s fmt.State, _ rune)
Format redacts personal metadata and values for all diagnostic verbs.
func (IdentifierProjection) LogValue ¶
func (IdentifierProjection) LogValue() slog.Value
LogValue prevents implicit structured-log disclosure.
func (IdentifierProjection) MarshalJSON ¶
func (IdentifierProjection) MarshalJSON() ([]byte, error)
MarshalJSON refuses implicit export; the feature owns explicit response fields.
func (IdentifierProjection) MarshalText ¶
func (IdentifierProjection) MarshalText() ([]byte, error)
MarshalText refuses implicit text and map-key disclosure.
func (IdentifierProjection) Values ¶
func (p IdentifierProjection) Values() (canonical, display string, present bool)
Values explicitly reveals the selected canonical/display values when they were included at construction. Zero and omitted projections return empty strings and false. The returned immutable strings are sensitive and must not be used as authority, logged, or copied into unprotected output.
type IdentifierProjectionBindings ¶
type IdentifierProjectionBindings struct {
TenantID TenantID
UserID UserID
IdentifierID IdentifierID
Kind IdentifierKind
Status Status
Verified bool
Primary bool
VerificationState VerificationState
UserVersion uint64
AuthorityVersion uint64
IdentifierVersion uint64
VerificationVersion uint64
VerifiedAt time.Time
ObservedAt time.Time
Values IdentifierValueVisibility
}
IdentifierProjectionBindings is a caller-owned immutable-by-convention copy of one observation's metadata. Versions are distinct positive dimensions and are never incremented by projection. VerifiedAt retains the original history; ObservedAt does not make it current authority. IDs and verification metadata remain personal data. Explicit output serialization belongs to the feature's authorized no-store response, not logs, caches or authorization decisions.
type IdentifierProjectionSpec ¶
type IdentifierProjectionSpec struct {
TenantID TenantID
UserID UserID
IdentifierID IdentifierID
State IdentifierState
Values IdentifierValueVisibility
ObservedAt time.Time
}
IdentifierProjectionSpec selects one row from a consistent, already-authorized primary partition. TenantID and UserID are the expected query/command scope, not scope inferred from the row. State may contain pending or revoked records and blocked users for authorized administrative inspection. ObservedAt is the owner's trusted observation sample, not a lease or proof of current validity. Construction validates the complete partition, not only the selected row. Keep the input slices immutable during construction; they are not retained. Explicit fields are sensitive; do not put the spec into diagnostic containers.
func (IdentifierProjectionSpec) Format ¶
func (IdentifierProjectionSpec) Format(s fmt.State, _ rune)
Format redacts the complete sensitive source partition and selection.
func (IdentifierProjectionSpec) LogValue ¶
func (IdentifierProjectionSpec) LogValue() slog.Value
LogValue prevents implicit structured-log disclosure of constructor input.
func (IdentifierProjectionSpec) MarshalJSON ¶
func (IdentifierProjectionSpec) MarshalJSON() ([]byte, error)
MarshalJSON refuses implicit source-partition export.
func (IdentifierProjectionSpec) MarshalText ¶
func (IdentifierProjectionSpec) MarshalText() ([]byte, error)
MarshalText refuses implicit constructor-input and map-key disclosure.
type IdentifierProofSpec ¶
type IdentifierProofSpec struct {
Command IdentifierCommand
Issuer, Audience, ID string
IssuedAt, ExpiresAt time.Time
}
IdentifierProofSpec is unsigned trusted ceremony output, never authorization or caller-asserted verification. Command.Proof must be zero. The configured signer may issue only after exact feature proofs and current policy succeed.
type IdentifierQuery ¶
IdentifierQuery is an exact tenant/user complete primary read. More than MaximumIdentifiers is unavailable, not silently truncated or guessed absent.
type IdentifierReceipt ¶
type IdentifierReceipt struct {
IdentifierID IdentifierID
Action IdentifierAction
ExpectedAuthorityVersion, AuthorityVersion uint64
// IntentDigest is the exact original IdentifierIntentDigest, never current
// authority or a published private-value index. Retain it only in the
// protected immutable receipt; public results never disclose it.
IntentDigest [32]byte
}
IdentifierReceipt records committed local admission, never current authority or feature challenge/provider success. It contains no identifier values. Identifier authority advances once; the owner also persists lifecycle events and required cascade admission. Terminal cleanup is not inferred from this.
type IdentifierRecoveryRequest ¶
type IdentifierRecoveryRequest struct {
CommandID CommandID
TenantID TenantID
UserID UserID
IdentifierID IdentifierID
Action IdentifierAction
ActorScope authorization.DecisionContext
}
IdentifierRecoveryRequest authorizes exact original record/action scope. Possession of a command ID alone never authorizes receipt disclosure.
type IdentifierRepository ¶
type IdentifierRepository interface {
GetIdentifierState(context.Context, IdentifierQuery) (IdentifierState, error)
}
IdentifierRepository is platform-owned, concurrency-safe primary storage. Reads must honor the bounded context, return a consistent full partition and ErrUserAbsent for absence. A cache or consumer-supplied store is not authority.
type IdentifierResult ¶
type IdentifierResult struct {
CommandID CommandID
CommitOutcome CommitOutcome
IdentifierID IdentifierID
Version, AuthorityVersion uint64
}
IdentifierResult keeps known commitment even when disclosure fails. Zero versions/ID on an error do not imply rollback; unknown requires scoped recovery.
type IdentifierService ¶
type IdentifierService struct {
// contains filtered or unexported fields
}
IdentifierService owns identity command admission, not sessions, challenges, normalization engines, transactions, caches or goroutines. All dependencies must be concurrency-safe and honor bounded contexts. Use trusted composition.
func NewIdentifierService ¶
func NewIdentifierService(repo IdentifierRepository, uow UnitOfWork, auth authorization.Service, redact RedactFunc, caps capability.Service, c IdentifierConfig) (*IdentifierService, error)
NewIdentifierService validates and freezes policy without external I/O.
func (*IdentifierService) IdentifierChange ¶
func (s *IdentifierService) IdentifierChange(ctx context.Context, r IdentifierChangeRequest) (out IdentifierResult, err error)
IdentifierChange authorizes before proof/primary access and again against current state. The sole owner checks replay before CAS, repeats locked fresh evidence/uniqueness/final access and atomically consumes proof/risk with state, keyed reuse tombstones, lifecycle events/audit and receipt. This service owns no durable reservation and cannot claim atomicity from a primary read alone.
func (*IdentifierService) RecoverIdentifierChange ¶
func (s *IdentifierService) RecoverIdentifierChange(ctx context.Context, r IdentifierRecoveryRequest) (out IdentifierResult, err error)
RecoverIdentifierChange reads only the exact original receipt under current record/action/owner policy; no Execute, proof consumption or challenge runs.
type IdentifierState ¶
type IdentifierState struct {
User User
Identifiers []Identifier
Verifications []Verification
AuthorityVersion uint64
}
IdentifierState is a complete, consistent primary tenant/user partition at the mutation lock boundary. Identifiers are strictly ID-ordered, at most 128; Verifications correspond positionally and exactly. AuthorityVersion is the tenant/user identifier dimension, not the user-authority dimension. All versions are positive. Do not mutate input collections during a call.
type IdentifierValueVisibility ¶
type IdentifierValueVisibility uint8
IdentifierValueVisibility is a closed output selection, not permission to inspect identifiers. Zero is invalid. The trusted feature owner must obtain current authorization and redaction policy before selecting either value.
const ( // IdentifierValuesOmitted retains metadata but no canonical or display value. IdentifierValuesOmitted IdentifierValueVisibility = iota + 1 // IdentifierValuesIncluded permits explicit Values access to the selected row. IdentifierValuesIncluded )
type IdentitySecurityEventV1 ¶
type IdentitySecurityEventV1 struct {
// contains filtered or unexported fields
}
IdentitySecurityEventV1 is the shared immutable profile builder. It owns no persistence or goroutine. The borrowed wall clock must be concurrency-safe; Build performs no callbacks under locks or database transactions. Copies share immutable primitive builders. The zero value is invalid.
func NewIdentitySecurityEventV1 ¶
func NewIdentitySecurityEventV1(wall clock.Clock) (*IdentitySecurityEventV1, error)
NewIdentitySecurityEventV1 selects exact profile limits and secure random record identities. A nil wall clock rejects; its panic/zero time is handled by the audit primitive. Caller retains clock ownership. No globals are changed.
func (*IdentitySecurityEventV1) Build ¶
func (b *IdentitySecurityEventV1) Build(ctx context.Context, input SecurityEventInput) (audit.Record, error)
Build returns an immutable, explicitly redacted canonical audit.Record with no structured mutation. It does not persist, buffer, retry or grant authority. Unsupported fields/actions and unsafe attribution return the stable sentinel; cancellation retains its identity and returns no record. RecordedAt belongs to the primitive builder clock, separately from trusted OccurredAt.
func (*IdentitySecurityEventV1) BuildDelivery ¶
func (b *IdentitySecurityEventV1) BuildDelivery(ctx context.Context, i DeliverySecurityEventInput) (audit.Record, error)
BuildDelivery builds the delivery subset of the shared immutable security profile. It never persists, retries or grants authority. OutcomeSucceeded means local bookkeeping was recorded; ambiguous provider evidence is a mark_unknown event, not OutcomeUnknown (reserved for an unknown commit). Accepted/retry/expiry/exhaustion/erasure do not claim provider confirmation. Exhaustion is local policy evidence and emits no provider-result assertion. Caller owns the bounded database transaction when it stages the result.
func (*IdentitySecurityEventV1) BuildRiskDecision ¶
func (b *IdentitySecurityEventV1) BuildRiskDecision(ctx context.Context, i RiskSecurityEventInput) (audit.Record, error)
BuildRiskDecision constructs the risk-decision subset of identity.security.v1 using the existing canonical audit record. Allow maps to succeeded/completed; deny, throttle and step-up map to denied with their closed registered reason. No provider attribution is fabricated and no structured mutation is asserted. Only user and genuine pre-auth attempt subjects are supported in this subset. Construction does not deliver audit, grant permission or prove a state commit. Nil/zero owners, malformed attribution and unknown decisions reject with ErrInvalidSecurityEvent and no record; context errors retain their identity. Concurrency and clock ownership follow IdentitySecurityEventV1.
type InProgressError ¶
InProgressError is a bounded nonterminal observation of the same command.
func (InProgressError) Error ¶
func (InProgressError) Error() string
type InvalidInputError ¶
type InvalidInputError struct{ Field string }
InvalidInputError classifies an invalid identity input without retaining its value. Field is a fixed schema field name, never user-supplied data. Error's text is deliberately constant, including for cross-tenant mismatches.
func (InvalidInputError) Error ¶
func (InvalidInputError) Error() string
Error returns the stable redacted validation diagnostic.
type LifecycleCascadeAdmission ¶
type LifecycleCascadeAdmission struct {
CascadeID CascadeID
Generation uint64
Kind LifecycleCascadeKind
TenantID TenantID
UserID UserID
IdentifierID IdentifierID
AuthorityVersion uint64
ManifestVersion string
Status RevocationStatus
Owners []RevocationOwnerReceipt
ExternalLimitations []PolicyReason
}
LifecycleCascadeAdmission is a historical pending owner admission, never authentication authority or asynchronous completion. Generation is initially one; AuthorityVersion is the identifier dimension for removal and change. Owners retains the exact manifest including unavailable consumers. Scope IDs are pseudonymous personal data; explicit JSON is for protected receipt storage or authorized projection. Treat values as immutable; Clone copies collections.
func (LifecycleCascadeAdmission) Clone ¶
func (r LifecycleCascadeAdmission) Clone() LifecycleCascadeAdmission
Clone returns caller-owned collections without changing admission identity.
func (LifecycleCascadeAdmission) Format ¶
func (LifecycleCascadeAdmission) Format(s fmt.State, _ rune)
Format omits pseudonymous scope and historical command correlation.
func (LifecycleCascadeAdmission) Validate ¶
func (r LifecycleCascadeAdmission) Validate(b CommandBinding) error
Validate checks exact pending admission shape and command scope, not database durability, current authority or consumer acknowledgement. Self and explicitly authorized administrative removal retain the target's scope, not the actor's. Native command admission owns authorization of a distinct human actor. Noncommitted outcomes must not carry this receipt; CommandResult enforces that distinction.
type LifecycleCascadeKind ¶
type LifecycleCascadeKind string
LifecycleCascadeKind names a selected identity-owned cascade, not completion. Unknown kinds deny until their exact scope and consumer contract is supported.
const ( // IdentifierRemovalCascade starts cleanup after the identifier authority // mutation. Old-address authentication must already deny at admission. IdentifierRemovalCascade LifecycleCascadeKind = "lifecycle.cascade.identifier_remove" // IdentifierChangeCascade starts cleanup after atomic identifier replacement. // The old value is already retired and cannot authenticate during cleanup. IdentifierChangeCascade LifecycleCascadeKind = "lifecycle.cascade.identifier_change" )
type ListUsersQuery ¶
type ListUsersQuery struct {
TenantID TenantID
Filters UserListFilters
Cursor Cursor
Limit uint32
Fields []FieldName
ExpiresAt time.Time
}
ListUsersQuery selects one authoritative stable snapshot. Users are ordered by the bytewise ascending canonical UserID, with no duplicates. A continuation must retain that snapshot and filters even when live directory state changes. Repositories must retain snapshots through ExpiresAt, scope them to TenantID and Filters, fail closed on expiry, and honor cancellation. Collections are call-owned; implementations must not mutate inputs or retain their aliases.
type LoginMethod ¶
type LoginMethod struct {
Credential CredentialRef
AccountID AccountID
Usable bool
ExpiresAt time.Time
}
LoginMethod is a primary authority-owned eligibility observation, never a caller assertion. Usable includes verification, enablement, policy/factor and provider availability. ExpiresAt zero means indefinite; otherwise expiry is exclusive. AccountID is mandatory only for provider methods. API keys never count as a replacement for a human login method, even if marked usable.
type MapClaimsFunc ¶
type MapClaimsFunc func(context.Context, ClaimsPolicyInput) (ClaimsPolicyDecision, error)
MapClaimsFunc is a concurrent-safe bounded pure verified-claim mapping.
type NormalizationPolicy ¶
type NormalizationPolicy string
NormalizationPolicy names a versioned composition-owned normalization rule. Identity delegates these rules; it does not own another Unicode/phone engine.
const ( NormalizeNone NormalizationPolicy = "none" NormalizeUnicodeNFC NormalizationPolicy = "unicode-nfc" NormalizeCaseFold NormalizationPolicy = "case-fold" NormalizeEmail NormalizationPolicy = "email" NormalizePhone NormalizationPolicy = "phone" )
type NormalizeAttributeFunc ¶
type NormalizeAttributeFunc func(context.Context, NormalizationPolicy, AttributeScalar) (AttributeScalar, error)
NormalizeAttributeFunc normalizes one admitted string scalar. The injected implementation must use stable versioned rules, preserve kind, honor context and be side-effect-free/concurrent-safe. Errors and panics are redacted.
type NotCommittedError ¶
type NotCommittedError struct{ CommandID CommandID }
NotCommittedError identifies authoritative abort/absence, never inferred rollback.
func (NotCommittedError) Error ¶
func (NotCommittedError) Error() string
type OperationContext ¶
type OperationContext struct {
OperationID string
TenantID TenantID
ActorID ActorID
CorrelationID string
Deadline time.Time
}
OperationContext is immutable operation correlation, never authentication or transaction authority. Deadline, when present, is the original exclusive execution bound; hook execution may narrow but never extend that instant.
type PolicyEvaluator ¶
type PolicyEvaluator struct {
// contains filtered or unexported fields
}
PolicyEvaluator validates copied typed input and output around the existing pure callbacks. It owns no authority, state, clock, locks or goroutines. Invalid input never reaches a callback. Errors/panics/cancellation/malformed decisions yield zero output; the evaluator never retries or substitutes policy.
func NewPolicyEvaluator ¶
func NewPolicyEvaluator(set PolicySet, cfg PolicyEvaluatorConfig) (*PolicyEvaluator, error)
NewPolicyEvaluator freezes composition without I/O, rejecting missing members.
func (*PolicyEvaluator) AssessRisk ¶
func (e *PolicyEvaluator) AssessRisk(ctx context.Context, in RiskPolicyInput) (RiskPolicyDecision, error)
AssessRisk validates the exact bound operation and returns no partial decision after failure. The valid RiskDeny/StepUp variants remain explicit outcomes.
Example ¶
package main
import (
"context"
"fmt"
"time"
"github.com/faustbrian/go-authorization/v3"
"github.com/faustbrian/go-identity"
)
// Example composition denies authorization. Real workflows must separately
// require the upstream service's current Allow; RiskAllow is not that grant.
type policyExampleAuthorizer struct{}
func (policyExampleAuthorizer) Decide(context.Context, authorization.Request) (authorization.Decision, error) {
return authorization.Decision{Outcome: authorization.Deny, Revision: 1}, nil
}
func main() {
authorize, err := authorization.NewDecisionService(policyExampleAuthorizer{})
if err != nil {
panic(err)
}
set := identity.PolicySet{
Authorize: authorize,
AssessRisk: func(context.Context, identity.RiskPolicyInput) (identity.RiskPolicyDecision, error) {
return identity.RiskPolicyDecision{Level: identity.RiskLow, Action: identity.RiskAllow, PolicyID: "example", PolicyVersion: 1, Reasons: []identity.PolicyReason{"safe"}}, nil
},
MapClaims: func(_ context.Context, in identity.ClaimsPolicyInput) (identity.ClaimsPolicyDecision, error) {
return identity.ClaimsPolicyDecision{Claims: in.Claims, PolicyID: "example", PolicyVersion: 1, Reason: "safe"}, nil
},
DecideRetention: func(context.Context, identity.RetentionPolicyInput) (identity.RetentionPolicyDecision, error) {
return identity.RetentionPolicyDecision{Disposition: identity.RetentionAllow, PolicyID: "example", PolicyVersion: 1, Reasons: []identity.PolicyReason{"safe"}}, nil
},
Redact: func(_ context.Context, in identity.RedactionPolicyInput) (identity.RedactionPolicyDecision, error) {
return identity.RedactionPolicyDecision{RedactedFields: in.Fields, PolicyID: "example", PolicyVersion: 1, Reason: "safe"}, nil
},
}
evaluator, err := identity.NewPolicyEvaluator(set, identity.PolicyEvaluatorConfig{PolicyID: "example", PolicyVersion: 1, Reasons: []identity.PolicyReason{"safe"}, MaximumDuration: time.Second})
if err != nil {
panic(err)
}
decision, err := evaluator.AssessRisk(context.Background(), identity.RiskPolicyInput{TenantID: "tenant-example", ActorID: "service-example", OperationID: "identity.user.create", PolicyVersion: 1, Signals: []identity.RiskSignal{}})
fmt.Println(decision.Action, err)
}
Output: allow <nil>
func (*PolicyEvaluator) DecideRetention ¶
func (e *PolicyEvaluator) DecideRetention(ctx context.Context, in RetentionPolicyInput) (RetentionPolicyDecision, error)
DecideRetention prevents a destructive allow under a legal hold. Blocking or deferral is a policy observation, never a terminal lifecycle acknowledgement.
func (*PolicyEvaluator) MapClaims ¶
func (e *PolicyEvaluator) MapClaims(ctx context.Context, in ClaimsPolicyInput) (ClaimsPolicyDecision, error)
MapClaims returns only a bounded lossless mapping with current policy identity. It does not verify provider signatures or grant any identity authority.
func (*PolicyEvaluator) Redact ¶
func (e *PolicyEvaluator) Redact(ctx context.Context, in RedactionPolicyInput) (RedactionPolicyDecision, error)
Redact requires an exact partition of requested fields. Explicit full denial is valid (all fields redacted); missing/duplicate/unrequested fields are not.
type PolicyEvaluatorConfig ¶
type PolicyEvaluatorConfig struct {
PolicyID string
PolicyVersion uint64
Reasons []PolicyReason
MaximumDuration time.Duration
}
PolicyEvaluatorConfig registers one immutable policy identity/version and 1..32 distinct safe reason codes (at most 64 bytes). MaximumDuration must be positive and no more than a minute. There are no implicit defaults.
type PolicyReason ¶
type PolicyReason string
PolicyReason is a registered diagnostic code, never user or secret data. Read composition registers at most 32 unique codes, each 1..64 UTF-8 bytes without ASCII whitespace or control characters.
type PolicySet ¶
type PolicySet struct {
Authorize authorization.Service
AssessRisk AssessRiskFunc
MapClaims MapClaimsFunc
DecideRetention DecideRetentionFunc
Redact RedactFunc
}
PolicySet has exactly the five owned composition members. Configure before concurrent use; NewPolicyEvaluator snapshots the callbacks. Authorize remains the exact upstream service, not an identity facade. Callbacks own no stores, transactions, routing or continuation. They must honor context deadlines; no detached goroutine attempts to preempt a misbehaving callback.
type PreAuthTransactionID ¶
type PreAuthTransactionID string
PreAuthTransactionID is a canonical non-zero 128-bit attempt/correlation ID. Its empty zero value is invalid. Immutable values are safe for concurrent reads. Possession grants no authentication, capability-use or transaction authority: consumers must bind the exact tenant, attempt and continuation.
func NewPreAuthTransactionID ¶
func NewPreAuthTransactionID() (PreAuthTransactionID, error)
NewPreAuthTransactionID reads exactly 16 crypto/rand bytes and rejects all-zero entropy. Failure returns an empty ID and ErrPreAuthTransactionIDEntropy.
func ParsePreAuthTransactionID ¶
func ParsePreAuthTransactionID(raw string) (PreAuthTransactionID, error)
ParsePreAuthTransactionID accepts only the canonical encoding of a non-zero 128-bit value, with bounded decoding and ErrInvalidPreAuthTransactionID on failure. Parsing never grants authority or reserves a database transaction.
Example ¶
package main
import (
"fmt"
"github.com/faustbrian/go-identity"
)
func main() {
id, err := identity.ParsePreAuthTransactionID("AQAAAAAAAAAAAAAAAAAAAA")
if err != nil {
return
}
fmt.Println(identity.FormatPreAuthTransactionID(id))
}
Output: AQAAAAAAAAAAAAAAAAAAAA
type PrivacyExportCheckpointV1 ¶
PrivacyExportCheckpointV1 is a primary visibility cut, not an aggregate version or timestamp. The initial empty projection commits position 1. Every earlier subject mutation must be visible; producers must retain this exact cut.
type PrivacyExportConfig ¶
type PrivacyExportConfig struct {
Query UserQueryConfig
ProofIssuer, ProofAudience string
MaximumProofAge time.Duration
EvidenceKeys []PrivacyExportEvidenceKey
}
PrivacyExportConfig freezes trusted policy, proof trust and retained snapshot keys. Keep historical keys through receipt retention; rotation never renews proof freshness or rewrites snapshot evidence. One to 32 unique keys are required. MaximumProofAge is positive and at most five minutes.
type PrivacyExportContributorBindingV1 ¶
type PrivacyExportContributorBindingV1 struct {
ContributorID string
ContractMajor uint16
ContractMinor uint16
ProjectionID PrivacyExportProjectionV1
ScopeKeyDigest [32]byte
Checkpoint PrivacyExportCheckpointV1
}
PrivacyExportContributorBindingV1 binds one complete subject cut. Version 1 uses contract/checkpoint 1.0 and the closed scope selector ["subject"] for every contributor: tenant, subject and contributor are separately MAC-bound.
type PrivacyExportContributorCutV1 ¶
type PrivacyExportContributorCutV1 struct {
ContributorID string
ProjectionID PrivacyExportProjectionV1
CheckpointPosition uint64
}
PrivacyExportContributorCutV1 is trusted owner's captured input. Position is positive; constructing it proves no authoritative read or durable admission.
type PrivacyExportEvidenceKey ¶
type PrivacyExportEvidenceKey struct {
// contains filtered or unexported fields
}
PrivacyExportEvidenceKey owns a copied versioned independent 256-bit HMAC integrity key. Zero is invalid. Retain versions through snapshot/evidence retention; rotation never re-MACs old records or changes recorded cuts. Key possession is trusted composition authority, never caller-provided config. This value has no destroy/zeroization guarantee in Go; manage retention at the secret owner. Immutable copies are concurrent-safe; never serialize it.
func NewPrivacyExportEvidenceKey ¶
func NewPrivacyExportEvidenceKey(version uint32, material [32]byte) (PrivacyExportEvidenceKey, error)
NewPrivacyExportEvidenceKey accepts positive version and nonzero key bytes. It validates structure, not key entropy, provenance or permission to seal.
func (PrivacyExportEvidenceKey) Format ¶
func (PrivacyExportEvidenceKey) Format(s fmt.State, _ rune)
func (PrivacyExportEvidenceKey) SealSnapshotV1 ¶
func (k PrivacyExportEvidenceKey) SealSnapshotV1(spec PrivacyExportSnapshotSpecV1) (PrivacyExportSnapshotV1, error)
SealSnapshotV1 copies and authenticates the complete closed input. It performs no storage writes or authorization. Only actual command admission may make an export runnable; callers must not use this constructor to attest locks/cuts.
func (PrivacyExportEvidenceKey) VerifySnapshotV1 ¶
func (k PrivacyExportEvidenceKey) VerifySnapshotV1(r PrivacyExportSnapshotRecordV1) (PrivacyExportSnapshotV1, error)
VerifySnapshotV1 reconstructs only exact V1 records under their retained key. Missing members, unknown versions, changed checkpoints or any MAC mismatch return zero. It never repairs, reorders, defaults, upgrades or renews evidence.
type PrivacyExportFragmentClassification ¶
type PrivacyExportFragmentClassification string
PrivacyExportFragmentClassification is closed; absence must be proved, not inferred from a missing response, empty data, cancellation or unavailable cut.
const ( // PrivacyExportFragmentData binds nonempty canonical redacted content. PrivacyExportFragmentData PrivacyExportFragmentClassification = "data" // PrivacyExportFragmentNotApplicable binds exact absence at the requested cut. PrivacyExportFragmentNotApplicable PrivacyExportFragmentClassification = "not-applicable" )
type PrivacyExportFragmentV1 ¶
type PrivacyExportFragmentV1 struct {
ExportID PrivacyExportJobID
TenantID TenantID
SubjectID UserID
CommandID CommandID
PrivacyEpoch uint64
EvidenceKeyVersion uint32
SnapshotDigest [32]byte
ContributorID string
ContractMajor uint16
ContractMinor uint16
ProjectionID PrivacyExportProjectionV1
ScopeKeyDigest [32]byte
RequestedCheckpoint PrivacyExportCheckpointV1
ObservedCheckpoint PrivacyExportCheckpointV1
SchemaMajor uint16
SchemaMinor uint16
Classification PrivacyExportFragmentClassification
ContentLength uint64
ContentDigest [32]byte
}
PrivacyExportFragmentV1 is exact returned metadata, never publication authority. The contributor owns canonical redaction/content schema and exact-cut reads; the coordinator must validate this binding and independently verify observed bytes before any publication. All schema/contract/checkpoint versions are 1.0. Content itself remains caller-owned, not retained here. Never log this value.
type PrivacyExportJobID ¶
type PrivacyExportJobID string
PrivacyExportJobID is a canonical nonzero 128-bit export identity. Possession grants neither download nor snapshot authority. Empty is invalid.
func NewPrivacyExportJobID ¶
func NewPrivacyExportJobID() (PrivacyExportJobID, error)
NewPrivacyExportJobID reads exactly 16 crypto/rand bytes; failures reveal no ID.
func ParsePrivacyExportJobID ¶
func ParsePrivacyExportJobID(raw string) (PrivacyExportJobID, error)
ParsePrivacyExportJobID accepts only the canonical 22-byte unpadded encoding.
type PrivacyExportProjectionSpecV1 ¶
type PrivacyExportProjectionSpecV1 struct {
ContributorID string
ProjectionID PrivacyExportProjectionV1
}
PrivacyExportProjectionSpecV1 declares the immutable projection profile for one contributor. It cannot submit a checkpoint: the durable request owner captures that cut under its admission transaction, never from caller input.
type PrivacyExportProjectionV1 ¶
type PrivacyExportProjectionV1 string
PrivacyExportProjectionV1 is a closed, storage-neutral immutable cut profile. Neither value names a table or permits reading mutable current state.
const ( // PrivacyExportSubjectJournalV1 requires exact subject-scoped append-only reads. PrivacyExportSubjectJournalV1 PrivacyExportProjectionV1 = "subject-journal-v1" // PrivacyExportStagedSubjectV1 requires a fragment staged in request admission. PrivacyExportStagedSubjectV1 PrivacyExportProjectionV1 = "staged-subject-fragment-v1" )
type PrivacyExportProofSpec ¶
type PrivacyExportProofSpec struct {
Command PrivacyExportRequestCommand
Issuer, Audience, ID string
IssuedAt, ExpiresAt time.Time
}
PrivacyExportProofSpec is unsigned trusted ceremony output. Command.Proof must be zero. Supplying it does not confer minting or reauthentication authority.
type PrivacyExportRecoveryRequest ¶
type PrivacyExportRecoveryRequest struct {
Intent PrivacyExportRequestCommand
ActorScope authorization.DecisionContext
}
PrivacyExportRecoveryRequest retains exact unsigned request intent and current authenticated human context. No expired proof is required or consumed.
type PrivacyExportRequest ¶
type PrivacyExportRequest struct {
Intent PrivacyExportRequestCommand
Proof capability.Proof
ActorScope authorization.DecisionContext
}
PrivacyExportRequest carries unsigned exact intent, the original opaque proof and authenticated upstream actor context. Intent.Proof must be zero. Binding policy/actor/schema must already match this service, so the signed digest is never silently rewritten. Do not mutate input concurrently during a call.
type PrivacyExportRequestCommand ¶
type PrivacyExportRequestCommand struct {
Binding CommandBinding
ExpectedIdentityVersion uint64
ExpectedAuthorityVersion uint64
ExpectedPrivacyEpoch uint64
SessionID string
SessionVersion uint64
MaximumBytes uint64
ArtifactTTL time.Duration
Projections []PrivacyExportProjectionSpecV1
Proof capability.Grant
}
PrivacyExportRequestCommand binds full-subject portable-JSON export intent. A trusted service must authorize the current human, verify configured proof issuer/audience/freshness and retain the original opaque proof for the durable owner. The owner must repeat those checks under locks, match all expected versions, allocate export ID and the next privacy epoch, capture all cuts, reserve/use the proof atomically, and persist queued admission. Construction does none of that and does not enable a worker or expose data. Concurrent mutation during construction is forbidden; Command owns a copied projection slice. Format is redacted. No arbitrary scope, format, cut or callback exists.
type PrivacyExportRequestReceipt ¶
type PrivacyExportRequestReceipt struct {
Status PrivacyExportStatus
Snapshot PrivacyExportSnapshotRecordV1
ExpectedAuthorityVersion uint64
ExpectedPrivacyEpoch uint64
MaximumBytes uint64
ArtifactTTL time.Duration
IntentDigest [32]byte
}
PrivacyExportRequestReceipt retains immutable queued-admission metadata in the existing command journal. Snapshot is the complete durable record, not an opaque value that would serialize as an empty object. Treat this mutable reconstruction shape as sensitive, caller-owned data; never log it or mutate it concurrently. Formatting is redacted. Structural validation is not MAC verification, authoritative cut capture, current eligibility or publication. Admission retains the captured user version and advances privacy epoch once; it does not invent an unrelated user/authority-version increment.
type PrivacyExportResult ¶
type PrivacyExportResult struct {
CommandID CommandID
CommitOutcome CommitOutcome
ExportID PrivacyExportJobID
Status PrivacyExportStatus
}
PrivacyExportResult reports command observation, not publication. Job metadata is returned only for a validated queued admission and authorized disclosure. Known CommitOutcome survives transport, cancellation and disclosure failures.
type PrivacyExportService ¶
type PrivacyExportService struct {
// contains filtered or unexported fields
}
PrivacyExportService admits exact proofs and validates request observations. It owns no storage, locks or goroutines. The platform PostgreSQL UnitOfWork remains the sole durable owner and must check current user/status/authority, real fresh session, legal/destruction eligibility, original proof and all cuts under its locks, atomically consume proof and persist queued admission. Replay and recovery must recheck current observation eligibility. This service cannot make a metadata-only or unimplemented owner safe. Dependencies must honor the bounded context and be concurrent-safe; construction performs no IO.
func NewPrivacyExportService ¶
func NewPrivacyExportService(uow UnitOfWork, caps capability.Service, authorize authorization.Service, redact RedactFunc, c PrivacyExportConfig) (*PrivacyExportService, error)
NewPrivacyExportService validates and copies trusted configuration. It rejects typed-nil dependencies, missing/duplicate retained keys and unbounded policy.
func (PrivacyExportService) Format ¶
func (PrivacyExportService) Format(s fmt.State, verb rune)
Format redacts runtime dependencies and retained integrity-key configuration.
func (PrivacyExportService) MarshalJSON ¶
func (PrivacyExportService) MarshalJSON() ([]byte, error)
MarshalJSON rejects serialization of runtime composition and retained keys.
func (*PrivacyExportService) Recover ¶
func (s *PrivacyExportService) Recover(ctx context.Context, r PrivacyExportRecoveryRequest) (out PrivacyExportResult, err error)
Recover queries the same scoped command under current authorization, matching retained unsigned intent and recorded evidence-key version. It never verifies an expired bearer, executes a mutation or allocates a replacement export ID.
func (*PrivacyExportService) Request ¶
func (s *PrivacyExportService) Request(ctx context.Context, r PrivacyExportRequest) (out PrivacyExportResult, err error)
Request authorizes the current self-service human before cryptographic work, verifies configured purpose/issuer/audience/age and hands the frozen original proof to the existing durable owner. Invalid owner observations are unknown, never invented rollback. Returned status is queued, never completed/ready.
type PrivacyExportSnapshotRecordV1 ¶
type PrivacyExportSnapshotRecordV1 struct {
SchemaMajor uint16
SchemaMinor uint16
ExportID PrivacyExportJobID
TenantID TenantID
SubjectID UserID
CommandID CommandID
IdentityVersion uint64
PrivacyEpoch uint64
LifecycleSequence uint64
ManifestVersion uint32
RequestedAtMicroseconds int64
Contributors []PrivacyExportContributorBindingV1
EvidenceKeyVersion uint32
Digest [32]byte
}
PrivacyExportSnapshotRecordV1 is caller-owned durable metadata, not a sealed value. VerifySnapshotV1 reconstructs it only after full structural/MAC checks. It contains pseudonymous personal data; do not log or use as authorization.
type PrivacyExportSnapshotSpecV1 ¶
type PrivacyExportSnapshotSpecV1 struct {
ExportID PrivacyExportJobID
TenantID TenantID
SubjectID UserID
CommandID CommandID
IdentityVersion uint64
PrivacyEpoch uint64
LifecycleSequence uint64
RequestedAtMicroseconds int64
Cuts []PrivacyExportContributorCutV1
}
PrivacyExportSnapshotSpecV1 is structural input, never authority. Trusted admission must capture all cuts while locking the actual identity, rejecting pending destructive state, and persist the complete sealed record atomically. V1 wire IDs require canonical nonzero 128-bit IDs; this does not normalize or rewrite imported directory IDs. An imported-ID profile requires explicit scope/schema reconciliation before admission, never silent conversion. RequestedAtMicroseconds is PostgreSQL UTC within years 1..9999. All counters are positive. Cuts must already be in exact manifest ASCII order.
type PrivacyExportSnapshotV1 ¶
type PrivacyExportSnapshotV1 struct {
// contains filtered or unexported fields
}
PrivacyExportSnapshotV1 is immutable integrity evidence, not current authority. It owns copied metadata, no IO, resources or goroutines. Concurrent reads are safe; zero is invalid. A valid MAC cannot prove a cut was read authoritatively, authorization, durable admission, worker eligibility or final publication.
func (PrivacyExportSnapshotV1) Contributor ¶
func (s PrivacyExportSnapshotV1) Contributor(id string) (PrivacyExportContributorBindingV1, bool)
Contributor returns an immutable exact binding; unknown/unbounded IDs fail.
func (PrivacyExportSnapshotV1) Record ¶
func (s PrivacyExportSnapshotV1) Record() PrivacyExportSnapshotRecordV1
Record returns an owned deep copy. Zero returns zero; it cannot be persisted or converted into valid evidence without the complete retained key profile.
func (PrivacyExportSnapshotV1) Valid ¶
func (s PrivacyExportSnapshotV1) Valid() bool
Valid reports construction/reconstruction, not current identity eligibility.
func (PrivacyExportSnapshotV1) ValidateFragment ¶
func (s PrivacyExportSnapshotV1) ValidateFragment(f PrivacyExportFragmentV1, canonical []byte, maximumBytes uint64) error
ValidateFragment checks the complete scope/version-vector binding, declared byte bound and digest of the actual canonical bytes. MaximumBytes is positive and at most 1 GiB. Bounds precede hashing; no bytes are copied or retained. NotApplicable requires zero bytes and SHA-256(empty); Data forbids empty data. This does not prove JSON canonicalization, schema/redaction or exact-cut reads: those are required from the registered contributor and composed coordinator. A valid fragment never authorizes download, publication or cascade closure.
type PrivacyExportStatus ¶
type PrivacyExportStatus string
PrivacyExportStatus is the closed export-job state, not a command commit outcome or proof of object erasure. Empty and unknown strings are invalid. A request receipt is always queued; only the durable worker and lifecycle owners may transition a job through the remaining states.
const ( // PrivacyExportQueued records admission pending contributor work. PrivacyExportQueued PrivacyExportStatus = "queued" // PrivacyExportRunning records a leased job, not completed publication. PrivacyExportRunning PrivacyExportStatus = "running" // PrivacyExportReady requires complete fragments and sealed publication. PrivacyExportReady PrivacyExportStatus = "ready" // PrivacyExportFailed denies download and requires object reconciliation. PrivacyExportFailed PrivacyExportStatus = "failed" // PrivacyExportCancelled denies download; it does not attest object erasure. PrivacyExportCancelled PrivacyExportStatus = "cancelled" // PrivacyExportExpired denies download and outstanding capabilities. PrivacyExportExpired PrivacyExportStatus = "expired" )
type ProfileConfig ¶
type ProfileConfig struct {
Fields UserCreationConfig
AllowedImageOrigins []string
}
ProfileConfig freezes field/time/current-policy composition and 1..32 exact canonical HTTPS image origins. Images are never fetched. No wildcard, userinfo, query, path, fragment or opaque origin is supported. Origins must match URL authority exactly; default ports are not silently equivalent to explicit ones.
type ProfileGetRequest ¶
type ProfileGetRequest struct {
TenantID TenantID
Context authorization.DecisionContext
}
ProfileGetRequest supplies trusted authenticated composition, never client JSON. The current human subject is the only target; resource ID must match it. Session validation is the session/transport owner, not these scope fields.
type ProfileGetResult ¶
type ProfileGetResult struct {
User UserProfile
Version uint64
}
ProfileGetResult is the current permission-filtered self projection.
type ProfileQuery ¶
ProfileQuery requests an exact subject/tenant projection from primary state. Fields is bounded and privately owned; no pagination, arbitrary target or cache is allowed. Repositories must return one consistent aggregate snapshot.
type ProfileRecord ¶
type ProfileRecord struct {
User User
Profile UserProfile
}
ProfileRecord is an authoritative internal-port snapshot. User and Profile must agree on tenant, subject and aggregate version. Only active users may self-service. User's lifecycle metadata never enters the public projection.
type ProfileRecoveryRequest ¶
type ProfileRecoveryRequest struct {
TenantID TenantID
CommandID CommandID
Context authorization.DecisionContext
}
ProfileRecoveryRequest performs current-subject scoped primary recovery only; no new fields, alternate target or mutation may be submitted.
type ProfileRepository ¶
type ProfileRepository interface {
GetProfile(context.Context, ProfileQuery) (ProfileRecord, error)
}
ProfileRepository owns consistent profile reads. GetProfile is bounded and concurrent-safe, returns ErrUserAbsent for absence, and never confers authority.
type ProfileService ¶
type ProfileService struct {
// contains filtered or unexported fields
}
ProfileService owns self-service reads, mutation and recovery without stores, workers or raw transactions. Dependencies remain caller-owned, bounded and concurrency-safe. Construction snapshots configuration without I/O.
func NewProfileService ¶
func NewProfileService(repo ProfileRepository, uow UnitOfWork, authorize authorization.Service, redact RedactFunc, config ProfileConfig) (*ProfileService, error)
NewProfileService composes the existing field, authorization and command owners.
func (*ProfileService) ProfileGet ¶
func (s *ProfileService) ProfileGet(ctx context.Context, req ProfileGetRequest) (out ProfileGetResult, err error)
ProfileGet returns only the exact current human subject's safe projection. Absence, blocking and output denial are indistinguishable ForbiddenError.
func (*ProfileService) ProfileUpdate ¶
func (s *ProfileService) ProfileUpdate(ctx context.Context, req ProfileUpdateRequest) (out ProfileUpdateResult, err error)
ProfileUpdate authorizes current state and every self-writable field before a stable command. New writes must CAS the locked version and active status after command replay lookup. Its one clock sample is reused for field decisions.
func (*ProfileService) RecoverProfileUpdate ¶
func (s *ProfileService) RecoverProfileUpdate(ctx context.Context, req ProfileRecoveryRequest) (out ProfileUpdateResult, err error)
RecoverProfileUpdate reads the original command under current subject/purpose authorization and redaction. Its result is historic, never login authority.
type ProfileUpdateCommand ¶
type ProfileUpdateCommand struct {
Binding CommandBinding
ExpectedVersion uint64
Name string
Image string
AdditionalFields []AttributeUpdate
}
ProfileUpdateCommand is immutable prepared intent for the existing command owner. Empty name/image are omitted; additional fields are whole replacements. New mutation requires the exact locked expected version and active status, one next version, immutable profile/result and identity.user.update audit. Replay must precede CAS. Structural construction is not authorization.
type ProfileUpdateRequest ¶
type ProfileUpdateRequest struct {
TenantID TenantID
Context authorization.DecisionContext
CommandID CommandID
SchemaVersion uint32
ExpectedVersion uint64
Name string
Image string
AdditionalFields []AttributeUpdate
CorrelationID string
}
ProfileUpdateRequest is the explicit-command core boundary. Empty Name/Image mean omitted, not clearing. Additional values retain false/zero/empty presence. ExpectedVersion is positive and cannot overflow its next version. Preserve CommandID and logical intent on retries; HTTP keyed/session/CSRF admission will compose this boundary and must not decode Context from a request body.
type ProfileUpdateResult ¶
type ProfileUpdateResult struct {
User UserProfile
InvalidationVersion uint64
CommandID CommandID
CommitOutcome CommitOutcome
}
ProfileUpdateResult preserves known outcome even when current disclosure fails. User/InvalidationVersion are zero when output is withheld. Invalid means no authoritative outcome observation, never inferred rollback of a prior attempt.
type ProviderRevocationOutcome ¶
type ProviderRevocationOutcome uint8
ProviderRevocationOutcome is an initial external-intent observation. Zero is invalid. Local commit never implies successful provider network revocation.
const ( ProviderRevocationNotRequested ProviderRevocationOutcome = iota + 1 ProviderRevocationPending )
type RecoveryQuery ¶
type RecoveryQuery struct {
CommandID CommandID
TenantID TenantID
UserID UserID
// AnonymousFlowID selects the explicit anonymous-flow namespace, mutually
// exclusive with UserID. Possession is never recovery authority.
AnonymousFlowID string `json:",omitempty"`
ActorID ActorID
ActorKind authorization.SubjectKind
OperationID string
RecordID string
LinkMode AccountLinkMode
}
RecoveryQuery scopes a primary-authority lookup to the original command, tenant, target, actor, operation and exact record/link mode for all outcomes. The owner must match every field against immutable command scope before returning any outcome, including conflict, not-committed and in-progress. Non-record operations omit RecordID/LinkMode. A command ID alone never permits public lookup. No fields, alternate command IDs, callbacks or transaction handles are accepted.
type RedactFunc ¶
type RedactFunc func(context.Context, RedactionPolicyInput) (RedactionPolicyDecision, error)
RedactFunc is the bounded, side-effect-free redaction policy callback.
type RedactionPolicyDecision ¶
type RedactionPolicyDecision struct {
VisibleFields []FieldName
RedactedFields []FieldName
PolicyID string
PolicyVersion uint64
Reason PolicyReason
}
RedactionPolicyDecision describes exactly which requested fields are visible or redacted, with one registered policy ID/version. Unknown, overlapping or duplicate field names are invalid. Empty visibility omits the projection.
type RedactionPolicyInput ¶
type RedactionPolicyInput struct {
TenantID TenantID
ViewerID ActorID
Resource RedactionResource
Fields []FieldName
OperationID string
PolicyVersion uint64
Deadline time.Time
}
RedactionPolicyInput binds the viewer, tenant, operation, policy revision and deadline to a copied bounded projection. Callbacks are side-effect-free, concurrent-safe and must honor the supplied context; no stores/transactions.
type RedactionResource ¶
RedactionResource binds the exact resource kind and target being projected.
type RequestIntent ¶
type RequestIntent struct {
// contains filtered or unexported fields
}
RequestIntent freezes complete request input before generated values, current-state preparation or command reservation. It is correlation input, never authentication, authorization, a reservation or an execution receipt. Zero is invalid. Copies are immutable and safe for concurrent reads. Raw passwords, bearers and provider tokens are forbidden: feature owners supply purpose-bound keyed digests and map every behavior-bearing field.
func NewRequestIntent ¶
func NewRequestIntent(fields []FeatureField) (RequestIntent, error)
NewRequestIntent validates and copies 0..128 distinct named scalars using FeatureField bounds, with at most 256 KiB total. Input order has no meaning; absent fields remain distinct from explicitly empty/false/zero values. Time preserves its microsecond-exact instant in UTC. No I/O or callbacks run. Invalid input returns redacted InvalidInputError and no usable intent. Do not mutate caller-owned input during construction. Owners still validate their native schema before admission; structural construction grants no authority.
Example ¶
package main
import (
"fmt"
identity "github.com/faustbrian/go-identity"
)
func main() {
intent, err := identity.NewRequestIntent([]identity.FeatureField{
{Name: "remember", Value: identity.FeatureValue{Kind: identity.FeatureBool, Bool: false}},
{Name: "expected.version", Value: identity.FeatureValue{Kind: identity.FeatureUint64, Uint64: 7}},
})
if err != nil {
panic(err)
}
// Only the trusted adapter uses the owned projection; diagnostics stay redacted.
fields, valid := intent.Fields()
fmt.Println(valid, len(fields), intent)
}
Output: true 2 identity.RequestIntent(redacted)
func (RequestIntent) Fields ¶
func (r RequestIntent) Fields() ([]FeatureField, bool)
Fields returns an owned scalar projection only for trusted adapter canonical mapping. It returns false for zero. Mutating the result never changes intent. The projection is not a disclosure boundary: never log, serialize or return its private values through HTTP. No I/O or callbacks run.
func (RequestIntent) Format ¶
func (RequestIntent) Format(s fmt.State, _ rune)
Format redacts every diagnostic verb, including %#v and %x.
func (RequestIntent) LogValue ¶
func (RequestIntent) LogValue() slog.Value
LogValue emits no request fields or digests.
func (RequestIntent) MarshalJSON ¶
func (RequestIntent) MarshalJSON() ([]byte, error)
MarshalJSON rejects implicit persistence and accidental HTTP disclosure.
func (RequestIntent) MarshalText ¶
func (RequestIntent) MarshalText() ([]byte, error)
MarshalText rejects implicit text disclosure of private request inputs.
type RetentionAction ¶
type RetentionAction string
RetentionAction identifies the protected privacy operation; zero is invalid.
const ( RetentionExport RetentionAction = "export" RetentionAnonymize RetentionAction = "anonymize" RetentionDelete RetentionAction = "delete" )
type RetentionDisposition ¶
type RetentionDisposition string
RetentionDisposition never represents completed deletion or export.
const ( RetentionAllow RetentionDisposition = "allow" RetentionBlockLegalHold RetentionDisposition = "block-legal-hold" RetentionRetainUntil RetentionDisposition = "retain-until" )
type RetentionPolicyDecision ¶
type RetentionPolicyDecision struct {
Disposition RetentionDisposition
RetainUntil time.Time
PolicyID string
PolicyVersion uint64
Reasons []PolicyReason
}
RetentionPolicyDecision carries registered reasons and optional UTC expiry. RetainUntil requires an instant after RequestedAt; other variants omit it.
type RetentionPolicyInput ¶
type RetentionPolicyInput struct {
TenantID TenantID
ActorID ActorID
SubjectID UserID
OperationID string
PolicyVersion uint64
Deadline time.Time
Resource RetentionResource
Action RetentionAction
LegalHold bool
RequestedAt time.Time
}
RetentionPolicyInput binds a privacy decision to trusted subject/actor, action, operation and policy version. LegalHold=false is an explicit valid input; it must come from authoritative composition, not a client assertion. RequestedAt is a required trusted timestamp, normalized to UTC without sampling a clock.
type RetentionResource ¶
RetentionResource identifies one owned resource, with an optional bounded ID.
type RevocationOutcome ¶
type RevocationOutcome struct {
CascadeID CascadeID
Generation uint64
AuthorityVersion uint64
Status RevocationStatus
Owners []RevocationOwnerReceipt
ExternalLimitations []PolicyReason
}
RevocationOutcome is a historical cascade observation, not current authority. Admission returns generation 1, a new random ID, the incremented user authority version and Pending. Owners names every required consumer as pending, never silently omitting an unavailable consumer or asserting its acknowledgement. ExternalLimitations are registered redacted codes, never provider errors. Treat slices as immutable; public service results are caller-owned copies.
type RevocationOwnerReceipt ¶
type RevocationOwnerReceipt struct {
Owner string
Status RevocationStatus
}
RevocationOwnerReceipt names one semantic owner, not a storage implementation. Pending names a required consumer without asserting its acknowledgement.
type RevocationStatus ¶
type RevocationStatus uint8
RevocationStatus separates pending cleanup from closed or unknown cleanup. Its zero value is invalid. A committed owner admission is always pending.
const ( RevocationPending RevocationStatus = iota + 1 RevocationCompleted RevocationUnknown )
type RiskAction ¶
type RiskAction string
RiskAction is a policy decision, not an authentication or consumption proof.
const ( RiskAllow RiskAction = "allow" RiskDeny RiskAction = "deny" RiskStepUp RiskAction = "step-up" )
type RiskLevel ¶
type RiskLevel string
RiskLevel classifies risk; the empty value is invalid, never implicitly low.
type RiskPolicyDecision ¶
type RiskPolicyDecision struct {
Level RiskLevel
Action RiskAction
PolicyID string
PolicyVersion uint64
Reasons []PolicyReason
}
RiskPolicyDecision has closed enums and 1..32 registered unique reasons. Deny and StepUp are valid decisions but never permission to perform a mutation.
type RiskPolicyInput ¶
type RiskPolicyInput struct {
TenantID TenantID
ActorID ActorID
SubjectID UserID
OperationID string
PolicyVersion uint64
Deadline time.Time
Signals []RiskSignal
}
RiskPolicyInput binds a pure risk decision to its exact operation and actor. SubjectID may be absent before registration; Signals must be explicit (a nonnil empty slice is valid). Deadline is narrowed to the bounded context.
type RiskSecurityDecision ¶
type RiskSecurityDecision string
RiskSecurityDecision is the closed risk classification, not authentication, revocation or a database/audit commit outcome. Zero is invalid.
const ( RiskSecurityAllow RiskSecurityDecision = "allow" RiskSecurityDeny RiskSecurityDecision = "deny" RiskSecurityThrottle RiskSecurityDecision = "throttle" RiskSecurityStepUp RiskSecurityDecision = "step_up" )
type RiskSecurityEventInput ¶
type RiskSecurityEventInput struct {
Decision RiskSecurityDecision
OccurredAt time.Time
TenantID TenantID
CommandID, CorrelationID, CausationID CommandID
Actor audit.ActorInput
Subject SecuritySubject
SubjectID, PolicyID string
PolicyVersion uint64
ImpersonationGrantID string
}
RiskSecurityEventInput is trusted risk-owner attribution for a non-mutating decision. Subject is a real authentication_attempt or known user; syntax does not establish provenance. ImpersonationGrantID is required exactly when the effective Actor has one DelegatedBy. Command/correlation identify the owning evaluation; optional causation retains an actual prior command or audit event. Caller owns attribution until BuildRiskDecision returns and must not mutate it concurrently. No provider facts, network, raw identifier, arbitrary reason, counter state or bearer can be attached to this input.
type RiskSignal ¶
type RiskSignal struct {
Name string
Value AttributeScalar
ObservedAt time.Time
}
RiskSignal is one bounded typed observation. Values must not contain secrets. Strings are at most 512 bytes; ObservedAt is required and normalized to UTC.
type SecurityAction ¶
type SecurityAction string
SecurityAction is a closed implemented subset of the security taxonomy. Further package actions require their owned field contract before support.
const ( SecurityHIBPQueryRange SecurityAction = "identity.hibp.query_range" SecurityHIBPDetectMatch SecurityAction = "identity.hibp.detect_match" SecurityHIBPRejectRange SecurityAction = "identity.hibp.reject_range" )
type SecurityEventInput ¶
type SecurityEventInput struct {
Action SecurityAction
OccurredAt time.Time
Outcome audit.Outcome
Reason SecurityReason
TenantID TenantID
CommandID, CorrelationID, CausationID CommandID
Actor audit.ActorInput
Subject SecuritySubject
SubjectID, PolicyID string
PolicyVersion uint64
Provider SecurityProvider
}
SecurityEventInput is trusted in-process attribution, not transport input. Its fields cannot contain arbitrary attributes, descriptions, network data, hashes, breach counts, raw claims or provider diagnostics. IDs must be stable canonical internal IDs, never credentials or raw user identifiers. Actor delegation is copied synchronously; callers must not mutate it during Build. Initial support is the HIBP action contract with a real authentication attempt subject and protected retention. Other action contracts fail closed. Command and correlation use command IDs. Causation additionally admits a canonical existing audit event ID carried unchanged in the named string type.
type SecurityProvider ¶
type SecurityProvider struct {
Kind SecurityProviderKind
Profile SecurityProviderProfile
Version uint64
Result SecurityProviderResult
}
SecurityProvider contains only registered safe provider attribution. Version is positive and encoded once as canonical decimal at the audit boundary.
type SecurityProviderKind ¶
type SecurityProviderKind string
SecurityProviderKind identifies an implemented provider without endpoint data.
const SecurityProviderHIBP SecurityProviderKind = "hibp"
type SecurityProviderProfile ¶
type SecurityProviderProfile string
SecurityProviderProfile is a registered immutable protocol/privacy profile.
const SecurityHIBPRange SecurityProviderProfile = "hibp.range.padded.v1"
const SecurityHIBPRangeUnpadded SecurityProviderProfile = "hibp.range.unpadded.v1"
SecurityHIBPRangeUnpadded identifies explicit range checking without response padding. It must never attest the recommended padded privacy profile.
type SecurityProviderResult ¶
type SecurityProviderResult string
SecurityProviderResult describes evidence, not password acceptance or storage.
const ( SecurityProviderAccepted SecurityProviderResult = "accepted" SecurityProviderResultDenied SecurityProviderResult = "denied" SecurityProviderResultTimeout SecurityProviderResult = "timeout" SecurityProviderThrottled SecurityProviderResult = "throttled" SecurityProviderMalformed SecurityProviderResult = "malformed" SecurityProviderAmbiguous SecurityProviderResult = "ambiguous" SecurityProviderBindingMismatch SecurityProviderResult = "binding_mismatch" SecurityProviderReplayed SecurityProviderResult = "replayed" )
type SecurityReason ¶
type SecurityReason string
SecurityReason is the bounded shared reason catalog, never free text.
const ( SecurityCompleted SecurityReason = "completed" SecurityInvalidInput SecurityReason = "invalid_input" SecurityNotAuthenticated SecurityReason = "not_authenticated" SecurityNotAuthorized SecurityReason = "not_authorized" SecurityNotFoundHidden SecurityReason = "not_found_hidden" SecurityConflict SecurityReason = "conflict" SecurityExpired SecurityReason = "expired" SecurityReplayed SecurityReason = "replayed" SecurityRateLimited SecurityReason = "rate_limited" SecurityRiskDenied SecurityReason = "risk_denied" SecurityStepUpRequired SecurityReason = "step_up_required" SecurityProviderDenied SecurityReason = "provider_denied" SecurityTimeout SecurityReason = "timeout" SecurityCancelled SecurityReason = "cancelled" SecurityCommitUnknown SecurityReason = "commit_unknown" )
type SecuritySubject ¶
type SecuritySubject string
SecuritySubject is a closed safe resource classification. Initial HIBP construction uses a real pre-auth transaction or authenticated issuer challenge, never an identifier, digest or fabricated attempt.
const SecurityAuthenticationAttempt SecuritySubject = "authentication_attempt"
const SecurityUser SecuritySubject = "user"
SecurityUser identifies a known internal user, never an email, phone number or provider subject. Imported canonical IDs remain unchanged.
type Sensitivity ¶
type Sensitivity string
Sensitivity is the registered data classification. Secret fields cannot be indexed or made output-readable. These values must never hold credentials.
const ( SensitivityPublic Sensitivity = "public" SensitivityPersonal Sensitivity = "personal" SensitivitySensitive Sensitivity = "sensitive" SensitivitySecret Sensitivity = "secret" )
type Status ¶
type Status string
Status is the closed persisted identity lifecycle state. Its zero value and unknown values are invalid. Status is not a pending cascade/job state.
const ( // StatusActive is eligible for authentication, subject to other authorities. StatusActive Status = "active" // StatusSuspended denies authentication until an explicit restore command. StatusSuspended Status = "suspended" // StatusBanned denies authentication until an explicit authorized unban. StatusBanned Status = "banned" // StatusAnonymized is terminal for authentication and personal identity. StatusAnonymized Status = "anonymized" // StatusDeleted is terminal and must never be restored by import or policy. StatusDeleted Status = "deleted" )
func (Status) AllowsAuthentication ¶
AllowsAuthentication reports only lifecycle eligibility, not authentication or authorization. Unknown, blocked and terminal states fail closed. Elapsed ban/suspension time does not implicitly restore state or old credentials.
type StatusPolicy ¶
type StatusPolicy struct {
AllowedTransitions []StatusTransition
MaximumSuspension time.Duration
IdentifierReuseCooldown time.Duration
BanRequiresReason bool
}
StatusPolicy describes allowed lifecycle transitions and retention bounds. Configure it before use and do not mutate it or its slice during concurrent reads. Consumers retaining configuration must own a deep copy. A false reason requirement and zero reuse cooldown are explicit valid choices. Zero policy is invalid; no implicit default edges or duration limits are applied.
func (StatusPolicy) CheckTransition ¶
func (p StatusPolicy) CheckTransition(from, to Status, hasReason bool, restriction time.Duration) error
CheckTransition checks one proposed edge without changing a user or granting authority. hasReason must come from the validated command. A zero restriction duration means indefinite suspension/ban; positive duration is allowed only for those target states and never exceeds MaximumSuspension. The command owner must separately authorize, version-fence, persist and acknowledge all required cascades before a terminal status is reported complete.
Example ¶
package main
import (
"fmt"
"time"
"github.com/faustbrian/go-identity"
)
func main() {
policy := identity.StatusPolicy{
AllowedTransitions: []identity.StatusTransition{
{From: identity.StatusActive, To: identity.StatusSuspended, ReasonRequired: true},
},
MaximumSuspension: 24 * time.Hour,
}
// This checks a proposed edge, not caller authorization or committed state.
fmt.Println(policy.CheckTransition(identity.StatusActive, identity.StatusSuspended, true, time.Hour))
fmt.Println(policy.CheckTransition(identity.StatusActive, identity.StatusSuspended, false, time.Hour))
}
Output: <nil> identity: invalid input
func (StatusPolicy) Validate ¶
func (p StatusPolicy) Validate() error
Validate checks all configuration before any transition decision. There must be 1..32 distinct edges, a positive suspension maximum up to 87,600 hours and a nonnegative reuse cooldown up to the same bound. Self edges, unknown states, deleted outgoing edges and anonymized edges other than deletion are invalid.
type StatusTransition ¶
StatusTransition permits one explicit directed edge. ReasonRequired applies to a validated command reason, not to authority or proof supplied by a caller.
type SubjectID ¶
type SubjectID string
SubjectID is the canonical 22-character unpadded base64url encoding of a non-zero 128-bit subject identifier. The zero value is invalid. Values are immutable and safe for concurrent reads; reconstruct wire values with ParseSubjectID. A SubjectID alone proves neither identity nor tenant authority.
func NewSubjectID ¶
NewSubjectID reads exactly 16 bytes from crypto/rand, rejects all-zero entropy and returns its canonical representation. Failure returns an empty ID and ErrSubjectIDEntropy. The function retains no caller state or resources.
func ParseSubjectID ¶
ParseSubjectID accepts only a canonical unpadded base64url encoding of 16 non-zero bytes. It checks the length before decoding; invalid input returns an empty ID and ErrInvalidSubjectID without disclosing the input.
Example ¶
package main
import (
"fmt"
"github.com/faustbrian/go-identity"
)
func main() {
id, err := identity.ParseSubjectID("AAAAAAAAAAAAAAAAAAAAAQ")
if err != nil {
return
}
fmt.Println(identity.FormatSubjectID(id))
}
Output: AAAAAAAAAAAAAAAAAAAAAQ
type TenantID ¶
type TenantID string
TenantID is a case-sensitive tenant identity of at most 128 UTF-8 bytes. The empty value is invalid. A tenant ID is not proof of tenant access.
type TypedClaim ¶
type TypedClaim struct {
Name string
Value AttributeScalar
Sensitivity Sensitivity
}
TypedClaim is a lossless scalar with explicit sensitivity. Secret values are forbidden in mapped claims; credentials are never policy inputs or outputs.
type UnauthenticatedError ¶
type UnauthenticatedError struct{}
UnauthenticatedError is missing human identity; it retains no caller data.
func (UnauthenticatedError) Error ¶
func (UnauthenticatedError) Error() string
type UnavailableError ¶
type UnavailableError struct{}
UnavailableError is a redacted dependency, panic or invalid-output failure.
func (UnavailableError) Error ¶
func (UnavailableError) Error() string
type UnitOfWork ¶
type UnitOfWork interface {
Execute(context.Context, Command) (CommandResult, error)
Recover(context.Context, RecoveryQuery) (CommandResult, error)
}
UnitOfWork is the storage-neutral durable command owner. Execute must enforce a global command-ID claim, exact tenant/actor/purpose/canonical-input binding, idempotency, user uniqueness including tombstones, and one atomic user/result/ required audit commit. Recover queries the primary, never a projection/cache. Implementations are concurrent-safe and bounded by ctx. They cannot infer NotCommitted from cancellation or return Committed without required effects. A PostgreSQL adapter alone maps typed commands to its concrete coordinator; the core exposes no participant registration, work handle or transaction.
type UnknownCommitError ¶
type UnknownCommitError struct{ CommandID CommandID }
UnknownCommitError requires scoped recovery of the same command, not a new ID.
func (UnknownCommitError) Error ¶
func (UnknownCommitError) Error() string
type UpdateUserCommand ¶
type UpdateUserCommand struct {
Binding CommandBinding
ExpectedVersion uint64
Attributes []AttributeUpdate
}
UpdateUserCommand is a whole-value typed-field update, never a status, credential, identifier or role transition. ExpectedVersion is positive and below uint64's maximum. The durable owner checks replay before fencing the locked current version/status, then atomically persists fields, next aggregate version, original command result and required identity.user.update audit. Deleted/anonymized users cannot be updated or resurrected. Structural command construction alone grants no authorization or schema-validation authority.
type User ¶
User is a versioned directory projection. Repository/UnitOfWork owns writes; callers treat returned values as immutable snapshots. Validation grants no access, changes no state and does not confirm lifecycle cascade completion.
func (User) Validate ¶
Validate checks a user projection against the exact expected tenant. It rejects malformed/oversized IDs, unknown statuses and zero versions without rewriting identifiers. It is structural validation only; canonical-ID policy, authoritative lookup, freshness and caller authorization remain separate.
Example ¶
package main
import (
"fmt"
"github.com/faustbrian/go-identity"
)
func main() {
user := identity.User{
ID: "01ARZ3NDEKTSV4RRFFQ69G5FAV", TenantID: "tenant-a",
Status: identity.StatusActive, Version: 1,
}
fmt.Println(user.Validate("tenant-a"))
fmt.Println(user.Validate("tenant-b"))
}
Output: <nil> identity: invalid input
type UserCreateRecoveryRequest ¶
type UserCreateRecoveryRequest struct {
CommandID CommandID
TenantID TenantID
UserID UserID
ActorScope authorization.DecisionContext
}
UserCreateRecoveryRequest cannot replace inputs or allocate a new command. ActorScope authorizes current creation-result access for the exact target.
type UserCreateRequest ¶
type UserCreateRequest struct {
CommandID CommandID
TenantID TenantID
UserID UserID
SchemaVersion uint32
Fields []AttributeUpdate
ActorScope authorization.DecisionContext
CorrelationID string
}
UserCreateRequest is the explicit-ID core command boundary. Trusted admission preallocates a random CommandID and stable canonical UserID; every retry keeps them and the same logical fields. HTTP keyed admission is a separate owned transport/adapter concern, not caller-written workflow glue. Fields are at most 64 explicit values; defaults may expand the prepared command to 128. ActorScope comes from trusted authentication composition, never client JSON.
type UserCreateResult ¶
type UserCreateResult struct {
CommandID CommandID
User User
CommitOutcome CommitOutcome
}
UserCreateResult preserves durable outcome even when output is withheld by cancellation or current redaction. User is disclosed only on permitted success. A committed result is an initial historical snapshot, not current login state. CommitOutcomeInvalid means this call made no authoritative outcome observation; it never implies that an earlier attempt with this command ID rolled back.
type UserCreationConfig ¶
type UserCreationConfig struct {
Query UserQueryConfig
Schema AttributeSchema
Normalize NormalizeAttributeFunc
ValidateValue ValidateAttributeFunc
}
UserCreationConfig is explicit immutable composition. Query supplies shared current authorization/redaction/time/ID policy. The schema, normalizer and validator are the same field-enforcement implementation used by typed writes.
type UserCreationService ¶
type UserCreationService struct {
// contains filtered or unexported fields
}
UserCreationService owns authorized creation and recovery orchestration. It has no stores, goroutines, locks, arbitrary participant callbacks or commits. The full identity Service will compose this same implementation and reads. Dependencies remain caller-owned and must be concurrent-safe/context-bounded.
func NewUserCreationService ¶
func NewUserCreationService(uow UnitOfWork, authorize authorization.Service, redact RedactFunc, config UserCreationConfig) (*UserCreationService, error)
NewUserCreationService validates and freezes composition without I/O.
func (*UserCreationService) RecoverUserCreate ¶
func (s *UserCreationService) RecoverUserCreate(ctx context.Context, req UserCreateRecoveryRequest) (result UserCreateResult, err error)
RecoverUserCreate authorizes current result access before a scoped primary lookup. It does not execute, rewrite fields, consume proofs or issue new IDs. Historic policy/schema bindings remain intact while current policy controls disclosure. Committed recovery does not assert current user status/freshness.
func (*UserCreationService) UserCreate ¶
func (s *UserCreationService) UserCreate(ctx context.Context, req UserCreateRequest) (result UserCreateResult, err error)
UserCreate admits/normalizes/authorizes before the first durable attempt. After Execute begins, malformed output, dependency failure or panic is Unknown unless a valid authoritative receipt proves another exact outcome. Required audit and logical command replay belong to that same adapter commit. Current redaction is reapplied after every committed replay; no stale grants survive.
type UserDirectoryRepository ¶
type UserDirectoryRepository interface {
UserQueryRepository
UserListRepository
}
UserDirectoryRepository composes reads and listing without a parallel store.
type UserGetRequest ¶
type UserGetRequest struct {
TenantID TenantID
UserID UserID
Context authorization.DecisionContext
}
UserGetRequest binds a target to an exact upstream authorization context. Trusted authenticated composition supplies Context; it must never be decoded from a client override. IDs and this request alone confer no authority.
type UserGetResult ¶
type UserGetResult struct{ User User }
UserGetResult is a permission-filtered directory snapshot, not a credential.
type UserID ¶
type UserID string
UserID identifies a directory user without encoding tenant or authority. It preserves an existing canonical ID, including a ULID, unchanged. Structural validation is not a substitute for the composition's canonical-ID policy. The empty value is invalid; IDs are case-sensitive and at most 128 bytes.
type UserListConfig ¶
type UserListConfig struct {
CursorKey [32]byte
CursorTTL time.Duration
ValidateCanonicalIdentifier func(context.Context, IdentifierKind, string) error
}
UserListConfig is immutable explicit cursor composition. CursorKey must be an independently generated 256-bit secret (all-zero is invalid). It must not be logged; rotation invalidates old cursors. TTL is positive, at most 15m. The canonical identifier validator is bounded, concurrency-safe and must validate without rewriting indexed values. Cursor possession grants no access.
type UserListFilters ¶
type UserListFilters struct {
Statuses []Status
IdentifierKind IdentifierKind
CanonicalIdentifier string
}
UserListFilters contains exact indexed filters; at least one known status is required, at most 16, without duplicates. Identifier kind/value are paired. CanonicalIdentifier is at most 512 UTF-8 bytes, never free-text search.
type UserListRepository ¶
type UserListRepository interface {
List(context.Context, ListUsersQuery) (UserPage, error)
}
UserListRepository owns authoritative snapshot selection and retention. Implementations must be concurrency-safe and obey ListUsersQuery semantics.
type UserListRequest ¶
type UserListRequest struct {
TenantID TenantID
Filters UserListFilters
Cursor string
Limit uint32
Context authorization.DecisionContext
}
UserListRequest binds a collection to a trusted authenticated upstream context. Resource type is identity.user.collection, ID is the exact tenant, and action is identity.user.list. The service overwrites reserved query attributes with the actual filters and limit, preventing dishonest bindings.
type UserListResult ¶
UserListResult contains only authorized/redacted users. NextCursor advances over all scanned rows, including omissions, without exposing hidden IDs.
type UserPage ¶
UserPage is a caller-owned bounded ordered snapshot page. Next is absent only at the end; otherwise its position advances exactly by len(Users). An empty page is terminal. No totals or storage diagnostics are disclosed.
type UserProfile ¶
type UserProfile struct {
ID UserID
TenantID TenantID
Name string
Image string
Version uint64
AdditionalFields []AttributeUpdate
}
UserProfile is the self-service projection. It deliberately has no email, status, roles, credentials or authentication authority. AdditionalFields are private copies filtered by schema output permission and current redaction. Version is the positive identity aggregate version, not session freshness. Formatting is redacted; explicit response serialization is caller-owned.
type UserQueryConfig ¶
type UserQueryConfig struct {
Clock clock.Clock
MaximumDuration time.Duration
PolicyID string
PolicyVersion uint64
RedactionReasons []PolicyReason
ValidateCanonicalUserID CanonicalUserIDValidator
}
UserQueryConfig is explicit immutable read composition. Clock is sampled once per call at authorization; MaximumDuration is positive and at most one minute. PolicyID/version bind both authorization and redaction. All callbacks and dependencies must be bounded and concurrency-safe; no implicit defaults. RedactionReasons is copied at construction and cannot be empty.
type UserQueryRepository ¶
type UserQueryRepository interface {
Get(context.Context, GetUserQuery) (User, error)
}
UserQueryRepository owns authoritative user reads. Implementations must be concurrent-safe, honor cancellation/deadlines, and return ErrUserAbsent for absence without leaking personal data. The full Repository will compose this narrow read seam with its write/list contracts; this is not a second store.
type UserQueryService ¶
type UserQueryService struct {
// contains filtered or unexported fields
}
UserQueryService is the shared user-read implementation. It owns no store, goroutines or locks and grants no caller identity. Its constructor permits an explicit read-only composition without mutation/capability dependencies; the full identity service composes this same query implementation.
func NewUserDirectoryService ¶
func NewUserDirectoryService(repo UserDirectoryRepository, authorize authorization.Service, redact RedactFunc, config UserQueryConfig, listConfig UserListConfig) (*UserQueryService, error)
NewUserDirectoryService composes the existing get implementation with listing; NewUserQueryService remains get-only. No repository or policy I/O is performed during construction and all configuration is copied.
func NewUserQueryService ¶
func NewUserQueryService(repo UserQueryRepository, authorize authorization.Service, redact RedactFunc, config UserQueryConfig) (*UserQueryService, error)
NewUserQueryService validates and snapshots the read composition without I/O. It rejects nil/typed-nil dependencies, missing policies and unbounded config.
func (*UserQueryService) UserGet ¶
func (s *UserQueryService) UserGet(ctx context.Context, req UserGetRequest) (result UserGetResult, err error)
UserGet admits scope before policy or storage work, requires explicit Allow at the selected policy revision, checks authoritative output and applies redaction before disclosure. No provider hints/role strings grant authority. Repository absence is indistinguishable from forbidden output. Cancellation, callback panic/error and malformed outputs fail closed with no user returned.
func (*UserQueryService) UserList ¶
func (s *UserQueryService) UserList(ctx context.Context, req UserListRequest) (result UserListResult, err error)
UserList authorizes before reading and reauthorizes every snapshot row before applying redaction. Every page uses one clock sample and one bounded context. Denied rows are omitted; dependency failures, panics, malformed pages and cancellation return no partial result. A cursor cannot renew its original expiry, change its query/viewer/tenant/policy, or authorize a later page.
type UserStatusCommand ¶
type UserStatusCommand struct {
Binding CommandBinding
ExpectedVersion uint64
ExpectedAuthorityVersion uint64
StatusPolicyVersion uint64
TargetStatus Status
Reason string
ExpiresAt time.Time
}
UserStatusCommand is immutable lifecycle intent. Both expected versions and absolute expiry are stable across retries; replay is checked before locked CAS. The owner fences both versions, checks the configured policy version and transition, bumps both counters once, and atomically stores status, expiry, audit, lifecycle event/outbox, immutable required-consumer snapshot and receipt. Suspend/ban emit identity.suspended.v1 and audit identity.user.suspend; restore/unban emit identity.restored.v1 and audit identity.user.restore. Restore is only from suspended; unban only from banned. Neither revives any pre-transition credential. Expiry requires an audited fresh restore command, never passive eligibility. Consumer closure is NOT part of admission.
func (UserStatusCommand) RequiredConsumers ¶
func (s UserStatusCommand) RequiredConsumers() []string
RequiredConsumers returns a caller-owned ordered copy of the exact immutable identity-lifecycle-consumers-v1 manifest for this operation. Adapters snapshot every ID and its public-contract fingerprint at admission; missing consumers cannot be omitted merely because they are not running. No acknowledgement is granted by this list or command construction.
type UserStatusConfig ¶
type UserStatusConfig struct {
Query UserQueryConfig
Policy StatusPolicy
PolicyVersion uint64
Reasons []string
}
UserStatusConfig is immutable explicit lifecycle composition. Reasons contains 1..32 unique registered UTF-8 codes, each at most 512 bytes without whitespace or controls. PolicyVersion identifies the frozen transition policy independently of authorization revision. No implicit expiry or transition defaults exist.
type UserStatusQuery ¶
UserStatusQuery is an exact partitioned primary lookup, never a cache read.
type UserStatusRecord ¶
UserStatusRecord is one consistent primary snapshot. AuthorityVersion is the user security dimension, not User.Version: profile writes may increment the latter alone. Every authority change must also advance User.Version.
type UserStatusRecoveryRequest ¶
type UserStatusRecoveryRequest struct {
CommandID CommandID
TenantID TenantID
UserID UserID
ActorScope authorization.DecisionContext
}
UserStatusRecoveryRequest looks up one original command under current policy. ActorScope.Action must name the original literal operation, not a new purpose.
type UserStatusRepository ¶
type UserStatusRepository interface {
GetStatus(context.Context, UserStatusQuery) (UserStatusRecord, error)
}
UserStatusRepository owns consistent bounded primary lifecycle reads. Absence returns ErrUserAbsent. The same durable identity owner implements UnitOfWork.
type UserStatusRequest ¶
type UserStatusRequest struct {
CommandID CommandID
TenantID TenantID
UserID UserID
ExpectedVersion uint64
ExpectedAuthorityVersion uint64
Reason string
ExpiresAt time.Time
ActorScope authorization.DecisionContext
CorrelationID string
}
UserStatusRequest is the explicit-ID core mutation boundary. ActorScope comes from trusted authenticated composition, never client JSON. Retain both expected versions, command ID, reason and absolute expiry on retries. Suspend/ban require a registered reason; restore/unban reject reason/expiry. Zero expiry means indefinite. Transport owns session freshness, CSRF and keyed HTTP admission.
type UserStatusResult ¶
type UserStatusResult struct {
CommandID CommandID
CommitOutcome CommitOutcome
User User
Revocation RevocationOutcome
}
UserStatusResult separates authoritative command outcome from disclosure. Withheld output leaves User/Revocation zero without erasing known commitment.
type UserStatusService ¶
type UserStatusService struct {
// contains filtered or unexported fields
}
UserStatusService owns policy and commands, not persistence, cleanup workers, transactions or goroutines. Dependencies/callbacks must be concurrency-safe.
func NewUserStatusService ¶
func NewUserStatusService(repo UserStatusRepository, uow UnitOfWork, authorize authorization.Service, redact RedactFunc, config UserStatusConfig) (*UserStatusService, error)
NewUserStatusService validates and copies configuration without I/O.
func (*UserStatusService) AdminUserBan ¶
func (s *UserStatusService) AdminUserBan(ctx context.Context, req UserStatusRequest) (UserStatusResult, error)
AdminUserBan requires literal identity.admin.user-ban authorization, not a role label. It bumps authority and admits pending cleanup exactly once.
func (*UserStatusService) AdminUserUnban ¶
func (s *UserStatusService) AdminUserUnban(ctx context.Context, req UserStatusRequest) (UserStatusResult, error)
AdminUserUnban restores only banned eligibility, not old credential authority.
func (*UserStatusService) RecoverUserStatus ¶
func (s *UserStatusService) RecoverUserStatus(ctx context.Context, req UserStatusRecoveryRequest) (result UserStatusResult, err error)
RecoverUserStatus performs a primary, exact-scope receipt lookup under current authorization, never Execute. The historical status is not current authority.
func (*UserStatusService) UserRestore ¶
func (s *UserStatusService) UserRestore(ctx context.Context, req UserStatusRequest) (UserStatusResult, error)
UserRestore restores only suspended eligibility with a fresh authority version; previously issued credentials never become usable again.
func (*UserStatusService) UserSuspend ¶
func (s *UserStatusService) UserSuspend(ctx context.Context, req UserStatusRequest) (UserStatusResult, error)
UserSuspend denies new authority and admits pending cleanup under explicit identity.user.suspend authorization. Commitment does not certify closure.
type UserUpdateAdminRecoveryRequest ¶
type UserUpdateAdminRecoveryRequest struct {
CommandID CommandID
TenantID TenantID
UserID UserID
ActorScope authorization.DecisionContext
}
UserUpdateAdminRecoveryRequest authorizes exact scoped historical result access without new fields, command IDs or a second mutation. It is not current state.
type UserUpdateAdminRequest ¶
type UserUpdateAdminRequest struct {
CommandID CommandID
TenantID TenantID
UserID UserID
ExpectedVersion uint64
SchemaVersion uint32
Fields []AttributeUpdate
ActorScope authorization.DecisionContext
CorrelationID string
}
UserUpdateAdminRequest is the explicit-ID core administrative update boundary. Trusted composition supplies the exact upstream ActorScope; role labels grant nothing. Retain command ID, target, expected version and logical fields on retries. Field schema/write rules apply to 1..64 updates without defaults. Keyed HTTP admission remains the platform transport/adapter's pending work.
type UserUpdateAdminResult ¶
type UserUpdateAdminResult struct {
CommandID CommandID
User User
Version uint64
CommitOutcome CommitOutcome
}
UserUpdateAdminResult separates a durable outcome from current disclosure. Version/User are zero on withheld output. Invalid means no authoritative command-outcome observation, never evidence that an earlier attempt rolled back.
type UserUpdateAdminService ¶
type UserUpdateAdminService struct {
// contains filtered or unexported fields
}
UserUpdateAdminService owns versioned field-update admission. It owns no stores, locks, goroutines or transactions. Dependencies must be bounded and concurrency-safe. Current row status/version is trusted only after exact authorization and scoped authoritative read; the adapter still fences races. Core/read/field/outcome enforcement reuses the existing implementations.
func NewUserUpdateAdminService ¶
func NewUserUpdateAdminService(repo UserQueryRepository, uow UnitOfWork, authorize authorization.Service, redact RedactFunc, config UserCreationConfig) (*UserUpdateAdminService, error)
NewUserUpdateAdminService freezes existing field and policy composition.
func (*UserUpdateAdminService) RecoverUserUpdateAdmin ¶
func (s *UserUpdateAdminService) RecoverUserUpdateAdmin(ctx context.Context, req UserUpdateAdminRecoveryRequest) (UserUpdateAdminResult, error)
RecoverUserUpdateAdmin is primary scoped recovery with current authorization and redaction; it never runs Execute or treats historical state as login state.
func (*UserUpdateAdminService) UserUpdateAdmin ¶
func (s *UserUpdateAdminService) UserUpdateAdmin(ctx context.Context, req UserUpdateAdminRequest) (result UserUpdateAdminResult, err error)
UserUpdateAdmin requires current operation and per-field Allow. A read-admission decision precedes state access, then apply decisions see the trusted row's status/version. The two phases replace caller metadata; neither implies an administrative role. The single clock sample is reused across both phases. Execute owns stale-version conflict versus same-command replay. Future expected versions are rejected before execution against older policy state.
type ValidateAttributeFunc ¶
type ValidateAttributeFunc func(context.Context, FieldPolicy, AttributeValue) error
ValidateAttributeFunc applies the composition's versioned field constraints after normalization and intrinsic bounds. Inputs are private copies; mutation cannot change prepared values or retained defaults. Implementations must be side-effect-free, bounded, concurrent-safe and contain no stores/workflows.
type Verification ¶
type Verification struct {
IdentifierID IdentifierID
State VerificationState
VerifiedAt time.Time
Version uint64
}
Verification records the identity-owned verification state of an exact IdentifierID. Version is independent of the identifier record's version; primary selection does not mint verification or reset its original time. VerifiedAt is absent for pending and may retain a historical time for revoked.
func (Verification) Format ¶
func (Verification) Format(s fmt.State, verb rune)
Format redacts verification metadata in diagnostic output.
func (Verification) Validate ¶
func (v Verification) Validate(identifier Identifier, now time.Time) error
Validate checks one identifier's consistent verification projection and one trusted current time. Persisted instants have microsecond precision; verified time is nonzero, no later than now and within years 1..9999. Nothing is fetched or consumed. In particular setting Verified does not prove a challenge.
type VerificationState ¶
type VerificationState uint8
VerificationState is closed persisted verification state, not a challenge or bearer. Pending requires a fresh feature-owned challenge; revoked is denied.
const ( VerificationPending VerificationState = iota + 1 VerificationVerified VerificationRevoked )
Source Files
¶
- account_link.go
- account_unlink.go
- accounts.go
- attributes.go
- cascade_admission.go
- command.go
- create.go
- credential_authority.go
- delivery_security_event.go
- feature_code.go
- feature_command.go
- feature_flow_bearer.go
- feature_operation.go
- feature_password_change.go
- feature_password_hash.go
- feature_password_reset.go
- feature_password_reset_input.go
- feature_password_signin.go
- feature_password_signup.go
- feature_password_signup_input.go
- feature_phone_password_reset.go
- feature_preauth_cookie.go
- feature_receipt.go
- feature_recovery_code.go
- feature_session_token.go
- hooks.go
- id.go
- idempotency_key.go
- identifier_access.go
- identifier_command.go
- identifier_projection.go
- identifier_removal_primary.go
- identifiers.go
- link_command.go
- list.go
- list_cursor.go
- policy.go
- privacy_command.go
- privacy_fragment.go
- privacy_receipt.go
- privacy_service.go
- privacy_snapshot.go
- profile.go
- query.go
- request_intent.go
- risk_security_event.go
- security_event.go
- status.go
- unlink_command.go
- update.go
- user.go
Directories
¶
| Path | Synopsis |
|---|---|
|
anonymous
module
|
|
|
postgres
module
|
|
|
delivery
module
|
|
|
postgres
module
|
|
|
email
module
|
|
|
http
module
|
|
|
anonymous
module
|
|
|
email
module
|
|
|
magiclink
module
|
|
|
mfa
module
|
|
|
otp
module
|
|
|
passkey
module
|
|
|
password
module
|
|
|
phone
module
|
|
|
session
module
|
|
|
i18n
module
|
|
|
internal
|
|
|
velocity
Package velocity carries private, immutable custody between the owned journal, native projection and reference composition.
|
Package velocity carries private, immutable custody between the owned journal, native projection and reference composition. |
|
magiclink
module
|
|
|
postgres
module
|
|
|
mfa
module
|
|
|
postgres
module
|
|
|
otp
module
|
|
|
postgres
module
|
|
|
password
module
|
|
|
postgres
module
|
|
|
phone
module
|
|
|
postgres
module
|
|
|
reference
module
|
|
|
risk
module
|
|
|
captcha
module
|
|
|
captcha/captchafox
module
|
|
|
captcha/hcaptcha
module
|
|
|
captcha/recaptcha
module
|
|
|
captcha/turnstile
module
|
|
|
hibp
module
|
|
|
postgres
module
|
|
|
valkey
module
|
|
|
session
module
|
|
|
postgres
module
|
|
|
username
module
|