identity

package
v0.1.0 Latest Latest
Warning

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

Go to latest
Published: Oct 2, 2026 License: Apache-2.0 Imports: 12 Imported by: 0

Documentation

Overview

Package identity provides immutable callers, owned claims and context transport. Construction validates representation; producers authenticate, and application policy authorizes. The package performs no network or signature verification.

Index

Examples

Constants

This section is empty.

Variables

View Source
var (
	// ErrInvalidCaller indicates invalid caller facts, provenance or options.
	ErrInvalidCaller = errors.New("identity: invalid caller")
	// ErrConflict indicates an attempt to replace an established caller.
	ErrConflict = errors.New("identity: caller conflict")
	// ErrInvalidClaims indicates malformed JSON, unsupported typed values, invalid UTF-8, nonfinite numbers, or excessive container nesting.
	ErrInvalidClaims = errors.New("identity: invalid claims")
	// ErrClaimsLimit indicates exhaustion of the wire or weighted byte allowance.
	ErrClaimsLimit = errors.New("identity: claims budget exceeded")
)

Functions

func NewContext

func NewContext(ctx context.Context, caller Caller) (context.Context, error)

NewContext returns a derived context carrying caller, for retrieval with FromContext. Anonymous on an empty context is a no-op. Any attempted installation over a nonanonymous caller, including an identical caller or anonymous, returns ErrConflict and a nil context. A nil context returns ErrInvalidCaller. Unrelated values are preserved.

Example
package main

import (
	"context"
	"errors"
	"fmt"

	"github.com/asteroid-computing/go-lambda-edge/identity"
)

func main() {
	// This validates a synthetic identifier;
	// it does not authenticate it.
	caller, err := identity.NewIAM("arn:aws:sts::123456789012:assumed-role/Worker/batch-1", identity.SourceCustomAssertion)
	if err != nil {
		panic(err)
	}
	ctx, err := identity.NewContext(context.Background(), caller)
	if err != nil {
		panic(err)
	}
	iam, _ := identity.FromContext(ctx).IAM()
	fmt.Println(iam.PrincipalARN())
	_, err = identity.NewContext(ctx, caller)
	fmt.Println(errors.Is(err, identity.ErrConflict))
}
Output:
arn:aws:sts::123456789012:assumed-role/Worker/batch-1
true

Types

type Caller

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

Caller is an immutable identity snapshot with exactly one JWT or IAM view. Its zero value is anonymous. Constructors validate facts; they neither authenticate nor authorize. Copies may be shared concurrently. There is no identity equality contract or implicit JSON export. Diagnostics omit facts.

func FromContext

func FromContext(ctx context.Context) Caller

FromContext returns the established caller or the anonymous zero value. Like ordinary context operations, it requires a nonnil context.

func NewIAM

func NewIAM(principalARN string, source Source, opts ...IAMOption) (Caller, error)

NewIAM validates and owns an exact root, user, assumed-role session or federated-user ARN. Bare role ARNs and policy patterns are not caller forms. Literal punctuation in a valid IAM user path is preserved without wildcard interpretation. Source must be gateway, custom assertion or verified IAM proof. Errors match ErrInvalidCaller and contain no supplied identifiers.

func NewJWT

func NewJWT(claims Claims, source Source, opts ...JWTOption) (Caller, error)

NewJWT validates normalized facts and retains immutable claims. It requires a nonempty issuer and a subject or client_id, without conflating those fields. Allowed sources are gateway, locally verified token and custom assertion. It does not verify signatures or expiry. Invalid inputs match ErrInvalidCaller; a dedicated-scope budget failure additionally matches ErrClaimsLimit.

Example
package main

import (
	"fmt"

	"github.com/asteroid-computing/go-lambda-edge/identity"
)

func main() {
	// Synthetic facts for this example.
	// In an application, an authenticating producer must establish these facts before constructing the caller.
	claims, err := identity.NewClaims(map[string]any{"iss": "https://issuer.example", "client_id": "batch-worker", "scope": "orders.read"})
	if err != nil {
		panic(err)
	}
	caller, err := identity.NewJWT(claims, identity.SourceCustomAssertion)
	if err != nil {
		panic(err)
	}
	jwt, _ := caller.JWT()
	client, _ := jwt.ClientID()
	_, hasSubject := jwt.Subject()
	scopes, known := jwt.Scopes()
	fmt.Println(client, hasSubject, scopes, known)
}
Output:
batch-worker false [orders.read] true

func (Caller) GoString

func (c Caller) GoString() string

GoString returns the same sanitized description as String.

func (Caller) IAM

func (c Caller) IAM() (IAM, bool)

IAM reports whether the caller has an IAM identity and returns an immutable view.

func (Caller) JWT

func (c Caller) JWT() (JWT, bool)

JWT reports whether the caller has a JWT identity and returns an immutable view.

func (Caller) Kind

func (c Caller) Kind() Kind

Kind returns the identity representation, or KindAnonymous for the zero value.

func (Caller) Source

func (c Caller) Source() Source

Source returns the attributed producer, or SourceNone for an anonymous caller.

func (Caller) String

func (c Caller) String() string

String describes kind and source without exposing identifiers or claims.

type Claim

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

Claim is an immutable view of a value. The zero value has kind ClaimInvalid. Its representation describes the available input, not authentication strength.

func (Claim) Array

func (c Claim) Array() ([]Claim, bool)

Array reports whether the claim is an array and returns a new slice of views. Replacing elements cannot mutate the original claims.

func (Claim) Bool

func (c Claim) Bool() (value, ok bool)

Bool reports whether the claim is a boolean and, if so, returns its value.

func (Claim) Float64

func (c Claim) Float64() (float64, bool)

Float64 explicitly converts a number to its nearest float64 representation. It reports false for nonnumbers or a conversion error; ordinary rounding is permitted. For supplied floating-point values it returns their stored value. Use NumberText and an exact parser when rounding is unacceptable.

func (Claim) GoString

func (c Claim) GoString() string

GoString returns the same sanitized description as String.

func (Claim) Kind

func (c Claim) Kind() ClaimKind

Kind returns the available semantic type.

func (Claim) NumberText

func (c Claim) NumberText() (string, bool)

NumberText reports whether an exact numeric representation is available. JSON and json.Number preserve their supplied literal; native integers use decimal text. Supplied float32/float64 and all strings return false, even for integral values. Exactness describes the supplied value, not lost upstream data.

func (Claim) Object

func (c Claim) Object() (Claims, bool)

Object reports whether the claim is an object and returns an immutable view.

func (Claim) Representation

func (c Claim) Representation() Representation

Representation returns the immediate input representation.

func (Claim) String

func (c Claim) String() string

String returns a diagnostic description without claim contents.

func (Claim) Text

func (c Claim) Text() (string, bool)

Text reports whether the claim is a string. It never converts other types.

type ClaimKind

type ClaimKind uint8

ClaimKind describes a claim's available semantic type.

const (
	ClaimInvalid ClaimKind = iota
	ClaimNull
	ClaimBoolean
	ClaimString
	ClaimNumber
	ClaimArray
	ClaimObject
)

Claim kinds distinguish a missing/zero view from a present null.

func (ClaimKind) String

func (k ClaimKind) String() string

String returns a stable lowercase name such as "number", or "ClaimKind(n)" for an undeclared value.

type Claims

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

Claims is an immutable object of named claims. Its zero value is empty. Views may share owned backing storage and may be read concurrently. Use Lookup and its checked accessors to inspect values; diagnostic formatting does not reveal claim names or contents. There is no implicit JSON export.

func NewClaims

func NewClaims(values map[string]any, opts ...ClaimsOption) (Claims, error)

NewClaims validates and owns already decoded values without a JSON round trip. Supported recursive values are nil, bool, string, built-in integers except uintptr, finite float32/float64, json.Number, map[string]any, map[string]string, []any and []string. Other defined types, pointers, structs and byte slices are rejected without calling user methods. A nil map is an empty object; a typed nil nested map/slice retains its object/array kind. A nil interface is null. Inputs must not change during construction; afterward they may be mutated. Invalid input matches ErrInvalidClaims; byte exhaustion is a ClaimsLimitError.

func NewTextClaims

func NewTextClaims(values map[string]string, opts ...ClaimsOption) (Claims, error)

NewTextClaims owns gateway text without parsing embedded JSON or numbers. All values retain RepresentationGatewayText. Nil means an empty object. Ownership, options and errors follow NewClaims.

Example
package main

import (
	"fmt"

	"github.com/asteroid-computing/go-lambda-edge/identity"
)

func main() {
	claims, err := identity.NewTextClaims(map[string]string{"cognito:groups": `["staff"]`})
	if err != nil {
		fmt.Println(err)
		return
	}
	claim, present := claims.Lookup("cognito:groups")
	_, array := claim.Array()
	fmt.Println("present:", present, "array:", array)
}
Output:
present: true array: false

func ParseClaims

func ParseClaims(data jsontext.Value, opts ...ClaimsOption) (Claims, error)

ParseClaims validates exactly one JSON object and owns its semantic contents. It preserves numeric token text, but not whitespace, member order or string escape spelling. It rejects duplicate names, invalid UTF-8 and trailing values. Input bytes must not change during construction and are not retained afterward. Invalid input matches ErrInvalidClaims; byte exhaustion is a ClaimsLimitError. The representation is received JSON, not proof of original JWT fidelity.

Example
package main

import (
	"encoding/json/jsontext"
	"fmt"

	"github.com/asteroid-computing/go-lambda-edge/identity"
)

func main() {
	claims, err := identity.ParseClaims(jsontext.Value(`{"tenant":"orders","sequence":9007199254740993}`))
	if err != nil {
		fmt.Println(err)
		return
	}
	if claim, present := claims.Lookup("sequence"); present {
		if number, exact := claim.NumberText(); exact {
			fmt.Println(number)
		}
	}
}
Output:
9007199254740993

func (Claims) GoString

func (c Claims) GoString() string

GoString returns the same sanitized description as String.

func (Claims) Len

func (c Claims) Len() int

Len returns the number of members in the object.

func (Claims) Lookup

func (c Claims) Lookup(name string) (Claim, bool)

Lookup reports whether name is present, including a present null value.

func (Claims) Names

func (c Claims) Names() []string

Names returns an independently owned, sorted slice of member names.

func (Claims) String

func (c Claims) String() string

String returns a diagnostic description without claim names or values.

type ClaimsLimitError

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

ClaimsLimitError describes a claims byte allowance failure. Its diagnostics contain no claim names, values, or underlying parser errors. The zero value has an unspecified maximum of zero.

func (*ClaimsLimitError) Error

func (e *ClaimsLimitError) Error() string

Error returns a sanitized description of the failure.

func (*ClaimsLimitError) Maximum

func (e *ClaimsLimitError) Maximum() int64

Maximum returns the configured allowance in bytes, or zero for a nil error.

func (*ClaimsLimitError) Unwrap

func (e *ClaimsLimitError) Unwrap() error

Unwrap returns ErrClaimsLimit.

type ClaimsOption

type ClaimsOption func(*claimsConfig)

ClaimsOption configures claims construction. A nil option is invalid. Scalar settings apply in order, with the last assignment winning.

func WithClaimsBudget

func WithClaimsBudget(bytes int) ClaimsOption

WithClaimsBudget sets the weighted resource allowance in bytes, defaulting to 256 KiB. Constructors reject a final setting outside 1..6 MiB. Each value costs 64 bytes plus object-name, string and exact-number text bytes. ParseClaims also limits the original JSON byte length to this maximum. The allowance is not an AWS quota or a heap cap. Nesting is limited separately to 64 containers, including the root, and cannot be disabled.

type IAM

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

IAM is an immutable view of an exact caller ARN and optional principal ID. Validation does not establish existence, credential possession or permission.

func (IAM) AccountID

func (i IAM) AccountID() string

AccountID returns the caller's twelve-digit account ID.

func (IAM) GoString

func (i IAM) GoString() string

GoString returns the same sanitized description as String.

func (IAM) Partition

func (i IAM) Partition() string

Partition returns the exact partition component.

func (IAM) PrincipalARN

func (i IAM) PrincipalARN() string

PrincipalARN returns the complete ARN, including any path and session name.

func (IAM) PrincipalID

func (i IAM) PrincipalID() (string, bool)

PrincipalID reports whether an opaque nonempty principal ID was supplied.

func (IAM) PrincipalType

func (i IAM) PrincipalType() IAMPrincipalType

PrincipalType returns the validated caller form.

func (IAM) Service

func (i IAM) Service() string

Service returns iam or sts, or empty for a zero IAM view.

func (IAM) String

func (i IAM) String() string

String returns a diagnostic description without identifiers.

type IAMOption

type IAMOption func(*iamConfig) error

IAMOption supplies an additional caller fact. Nil and duplicate options fail.

func WithIAMAccountID

func WithIAMAccountID(account string) IAMOption

WithIAMAccountID cross-checks an independently supplied caller account against the ARN. Do not pass API Gateway's API-owner requestContext.accountId here.

func WithIAMPrincipalID

func WithIAMPrincipalID(id string) IAMOption

WithIAMPrincipalID preserves a nonempty UTF-8 principal identifier opaquely. It is not parsed into an identity or treated as evidence of authentication.

type IAMPrincipalType

type IAMPrincipalType uint8

IAMPrincipalType describes the supported request-caller form, not an IAM resource-policy Principal expression.

const (
	IAMPrincipalUnknown IAMPrincipalType = iota
	IAMPrincipalRoot
	IAMPrincipalUser
	IAMPrincipalAssumedRole
	IAMPrincipalFederatedUser
)

Supported IAM principal forms preserve session identities.

func (IAMPrincipalType) String

func (t IAMPrincipalType) String() string

String returns a stable lowercase name such as "assumed_role", or "IAMPrincipalType(n)" for an undeclared value.

type JWT

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

JWT is an immutable view of normalized JWT facts and their owned claims. It makes no assertions about token validity, flow, expiry or permissions. Its zero value contains no identity facts.

func (JWT) Audience

func (j JWT) Audience() ([]string, bool)

Audience returns a copied sorted set and reports whether its meaning is known. Gateway string audiences remain available in Claims but are not split or parsed.

func (JWT) Claims

func (j JWT) Claims() Claims

Claims returns an immutable view of the original supplied claims.

func (JWT) ClientID

func (j JWT) ClientID() (string, bool)

ClientID reports whether a nonempty client_id was supplied.

func (JWT) CognitoGroups

func (j JWT) CognitoGroups() ([]string, bool)

CognitoGroups returns a copied sorted set of cognito:groups when interpretable. It does not promote arbitrary groups or roles claims into Cognito groups.

func (JWT) GoString

func (j JWT) GoString() string

GoString returns the same sanitized description as String.

func (JWT) Issuer

func (j JWT) Issuer() string

Issuer returns the exact issuer, or empty for a zero JWT.

func (JWT) Scopes

func (j JWT) Scopes() ([]string, bool)

Scopes returns a copied sorted set, distinguishing known empty from unavailable.

func (JWT) String

func (j JWT) String() string

String returns a diagnostic description without identity facts.

func (JWT) Subject

func (j JWT) Subject() (string, bool)

Subject reports whether a nonempty subject was supplied.

func (JWT) TokenUse

func (j JWT) TokenUse() (string, bool)

TokenUse reports whether a nonempty token_use was supplied.

type JWTOption

type JWTOption func(*jwtConfig) error

JWTOption supplies a separate assertion. Nil or duplicate options are invalid.

func WithGatewayScopes

func WithGatewayScopes(scopes []string) JWTOption

WithGatewayScopes supplies API Gateway's dedicated scopes collection. It is valid only with SourceGatewayAssertion. Nil means unavailable; a nonnil empty slice means known empty. Interpretable claim scopes must agree as exact sets. The supplied collection consumes the claims' remaining weighted budget before copying, even when its values duplicate a claim. Do not mutate it during NewJWT.

type Kind

type Kind uint8

Kind identifies the caller's mutually exclusive identity representation.

const (
	KindAnonymous Kind = iota
	KindJWT
	KindIAM
)

Caller kinds include an anonymous zero value.

func (Kind) String

func (k Kind) String() string

String returns a stable lowercase name such as "jwt", or "Kind(n)" for an undeclared value.

type Representation

type Representation uint8

Representation describes the immediate input representation, not its original token encoding or whether an authenticating producer verified it.

const (
	RepresentationUnknown Representation = iota
	RepresentationJSON
	RepresentationDecoded
	RepresentationGatewayText
)

Claim representations retain the distinction between JSON, decoded values, and gateway text that may have lost its original JSON type.

func (Representation) String

func (r Representation) String() string

String returns a stable lowercase name such as "gateway_text", or "Representation(n)" for an undeclared value.

type Source

type Source uint8

Source records the producer's assertion, not cryptographic evidence. Trusted application code must authenticate inputs before attributing a source.

const (
	SourceNone Source = iota
	SourceGatewayAssertion
	SourceLocallyVerifiedToken
	SourceCustomAssertion
	SourceVerifiedIAMProof
)

Sources distinguish gateway assertions, verified tokens, custom mappings and IAM proofs verified online by STS. None is reserved for anonymous callers.

func (Source) String

func (s Source) String() string

String returns a stable lowercase name such as "verified_iam_proof", or "Source(n)" for an undeclared value.

Jump to

Keyboard shortcuts

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