Documentation
¶
Overview ¶
Package api provides HTTP handlers for the Warden authorization engine.
Index ¶
- type API
- type AssignRoleRequest
- type AssignmentListResponse
- type AttachPermissionRequest
- type AuthZenAction
- type AuthZenEvaluationRequest
- type AuthZenEvaluationResponse
- type AuthZenEvaluationsRequest
- type AuthZenEvaluationsResponse
- type AuthZenResource
- type AuthZenSubject
- type AuthorizerFunc
- type BatchCheckRequest
- type BatchCheckResponse
- type CheckLogListResponse
- type CheckRequest
- type CheckResponse
- type ConditionInput
- type CreatePermissionRequest
- type CreatePolicyRequest
- type CreateResourceTypeRequest
- type CreateRoleRequest
- type DeleteRelationRequest
- type DetachPermissionRequest
- type GetAssignmentRequest
- type GetPermissionRequest
- type GetPolicyRequest
- type GetResourceTypeRequest
- type GetRoleRequest
- type ListAssignmentsRequest
- type ListCheckLogsRequest
- type ListPermissionsRequest
- type ListPoliciesRequest
- type ListRelationsRequest
- type ListResourceTypesRequest
- type ListResponse
- type ListRolesRequest
- type ListSubjectRolesRequest
- type MatchInfo
- type Option
- type PermissionDefInput
- type PermissionListResponse
- type PolicyListResponse
- type RelationDefInput
- type RelationListResponse
- type ResourceTypeListResponse
- type RoleListResponse
- type SubjectRolesResponse
- type UpdatePolicyRequest
- type UpdateRoleRequest
- type WriteRelationRequest
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type API ¶
type API struct {
// contains filtered or unexported fields
}
API wires all Warden HTTP handlers together.
func New ¶
New creates an API from an Engine and a Forge router. The router is only where Handler registers the routes; pass nil to have Handler build a fresh one of its own. RegisterRoutes ignores it and uses the router it is given. Every route is authenticated and authorized by default: an unauthenticated request gets 401, and a caller without the mapped permission gets 403. Pass AllowAnonymousChecks() to open the three check endpoints to callers with no resolved identity, and WithAuthorizer to replace the default engine-backed authorization decision.
func (*API) Handler ¶
Handler returns the fully assembled http.Handler with all routes, at /v1/... and the AuthZEN /access/v1/... on the router passed to New (a fresh one when that was nil).
The routes are registered on the first call only, and every later call returns the same handler, so calling Handler twice never registers the routes twice. When that registration fails, Handler panics with the error, and every later call panics with the same error, since the router is left half registered.
func (*API) RegisterRoutes ¶
RegisterRoutes registers all API routes into the given Forge router.
Every route is wrapped with identity, scope and IP-capture middleware: an unauthenticated request gets 401 (except the three check endpoints when AllowAnonymousChecks is set), and a request resolving to no tenant gets 400. Per-route authorization (manage/read/check/read_audit against "warden:<entity>") is attached individually by each registerXRoutes function, since the action and resource differ per route.
The middleware is attached via router.Use, not forge.WithGroupMiddleware on a wrapping Group: this router implementation does not propagate a Group's middleware down into sub-Groups created from it (each registerXRoutes function calls router.Group("/v1", ...) again), so wrapping would silently register every route with no auth at all. Router.Use does propagate to subgroups. Unlike Router.UseGlobal, it also stays scoped to this router and its children, rather than leaking onto sibling routes an embedding application registered elsewhere on the same top-level router.
type AssignRoleRequest ¶
type AssignRoleRequest struct {
RoleID string `json:"role_id" description:"Role ID to assign"`
SubjectKind string `json:"subject_kind" description:"Subject type"`
SubjectID string `json:"subject_id" description:"Subject identifier"`
ResourceType string `json:"resource_type,omitempty" description:"Scope to resource type"`
ResourceID string `json:"resource_id,omitempty" description:"Scope to resource ID"`
ExpiresAt string `json:"expires_at,omitempty" description:"Expiration time (RFC3339)"`
}
AssignRoleRequest is the body for assigning a role to a subject.
type AssignmentListResponse ¶
type AssignmentListResponse struct {
Body any `json:"assignments" body:"" description:"List of assignments"`
}
AssignmentListResponse wraps a list of assignments.
type AttachPermissionRequest ¶
type AttachPermissionRequest struct {
RoleID string `path:"roleId" description:"Role ID"`
PermissionID string `json:"permission_id,omitempty" description:"Permission ID (legacy; resolved to a name+namespace ref)"`
PermissionName string `json:"permission_name,omitempty" description:"Permission name (e.g. \"document:read\")"`
PermissionNamespacePath string `json:"permission_namespace_path,omitempty" description:"Namespace path of the permission (defaults to tenant root)"`
}
AttachPermissionRequest is the body for attaching a permission to a role.
After Phase A.5 the junction is keyed by natural keys (perm_namespace_path, perm_name) rather than typeids. Provide either:
- PermissionID — legacy form; the handler resolves it to a Ref by calling GetPermission once.
- PermissionName + optional PermissionNamespacePath — preferred natural form; what the DSL applier uses internally.
At least one of the two forms is required; if both are provided the name form wins.
type AuthZenAction ¶ added in v1.5.2
type AuthZenAction struct {
Name string `json:"name"`
Properties map[string]any `json:"properties,omitempty"`
}
AuthZenAction is the AuthZEN action (what the subject wants to do).
type AuthZenEvaluationRequest ¶ added in v1.5.2
type AuthZenEvaluationRequest struct {
Subject AuthZenSubject `json:"subject"`
Action AuthZenAction `json:"action"`
Resource AuthZenResource `json:"resource"`
Context map[string]any `json:"context,omitempty"`
}
AuthZenEvaluationRequest is a single AuthZEN access-evaluation request.
type AuthZenEvaluationResponse ¶ added in v1.5.2
type AuthZenEvaluationResponse struct {
Decision bool `json:"decision"`
Context map[string]any `json:"context,omitempty"`
}
AuthZenEvaluationResponse is an AuthZEN decision. Additional Warden detail (decision code, reason, matched rules, obligations) is exposed via Context.
type AuthZenEvaluationsRequest ¶ added in v1.5.2
type AuthZenEvaluationsRequest struct {
Subject *AuthZenSubject `json:"subject,omitempty"`
Action *AuthZenAction `json:"action,omitempty"`
Resource *AuthZenResource `json:"resource,omitempty"`
Context map[string]any `json:"context,omitempty"`
Evaluations []AuthZenEvaluationRequest `json:"evaluations"`
}
AuthZenEvaluationsRequest is the boxcarred ("evaluations") batch form. The top-level subject/action/resource/context act as defaults for items that omit them.
type AuthZenEvaluationsResponse ¶ added in v1.5.2
type AuthZenEvaluationsResponse struct {
Evaluations []AuthZenEvaluationResponse `json:"evaluations"`
}
AuthZenEvaluationsResponse is the batch decision list.
type AuthZenResource ¶ added in v1.5.2
type AuthZenResource struct {
Type string `json:"type"`
ID string `json:"id"`
Properties map[string]any `json:"properties,omitempty"`
}
AuthZenResource is the AuthZEN resource (the target of the request).
type AuthZenSubject ¶ added in v1.5.2
type AuthZenSubject struct {
Type string `json:"type"`
ID string `json:"id"`
Properties map[string]any `json:"properties,omitempty"`
}
AuthZenSubject is the AuthZEN subject (the actor requesting access).
type AuthorizerFunc ¶ added in v1.7.0
AuthorizerFunc decides whether the current caller may perform action on resource (a "warden:<entity>" string, e.g. "warden:role"). The default implementation, installed when no WithAuthorizer option is given, resolves the caller's warden.Actor from context and runs it back through the engine as a warden.CheckRequest.
type BatchCheckRequest ¶
type BatchCheckRequest struct {
Checks []CheckRequest `json:"checks" description:"List of authorization checks"`
}
BatchCheckRequest contains multiple checks.
type BatchCheckResponse ¶
type BatchCheckResponse struct {
Results []CheckResponse `json:"results" description:"Check results in order"`
}
BatchCheckResponse contains results for multiple checks.
type CheckLogListResponse ¶
type CheckLogListResponse struct {
Body any `json:"check_logs" body:"" description:"List of check logs"`
}
CheckLogListResponse wraps a list of check log entries.
type CheckRequest ¶
type CheckRequest struct {
SubjectKind string `json:"subject_kind,omitempty" description:"Subject type (user, api_key, service, service_acct)"`
SubjectID string `json:"subject_id" description:"Subject identifier"`
Action string `json:"action" description:"Action name"`
ResourceType string `json:"resource_type" description:"Resource type"`
ResourceID string `json:"resource_id,omitempty" description:"Resource identifier"`
Context map[string]any `json:"context,omitempty" description:"Additional context attributes"`
}
CheckRequest is the request body for an authorization check.
type CheckResponse ¶
type CheckResponse struct {
Allowed bool `json:"allowed" description:"Whether the request is allowed"`
Decision string `json:"decision" description:"Decision code"`
Reason string `json:"reason,omitempty" description:"Human-readable reason"`
MatchedBy []MatchInfo `json:"matched_by,omitempty" description:"Matched rules"`
EvalTimeNs int64 `json:"eval_time_ns" description:"Evaluation time in nanoseconds"`
Error string `json:"error,omitempty" description:"Per-item error (batch responses only)"`
}
CheckResponse is the response for an authorization check.
type ConditionInput ¶
type ConditionInput struct {
Field string `json:"field" description:"Dot-separated field path (e.g. context.ip)"`
Operator string `json:"operator" description:"Comparison operator"`
Value any `json:"value" description:"Expected value"`
}
ConditionInput is the input format for a policy condition.
type CreatePermissionRequest ¶
type CreatePermissionRequest struct {
Name string `json:"name" description:"Permission name (e.g. document:read)"`
Resource string `json:"resource" description:"Resource type"`
Action string `json:"action" description:"Action name"`
Description string `json:"description,omitempty" description:"Human-readable description"`
Metadata map[string]any `json:"metadata,omitempty" description:"Custom metadata"`
}
CreatePermissionRequest is the body for creating a permission.
type CreatePolicyRequest ¶
type CreatePolicyRequest struct {
Name string `json:"name" description:"Policy name"`
Description string `json:"description,omitempty" description:"Human-readable description"`
Effect string `json:"effect" description:"Policy effect (allow or deny)"`
Priority int `json:"priority,omitempty" description:"Policy priority"`
IsActive bool `json:"is_active,omitempty" description:"Whether the policy is active"`
NotBefore *time.Time `json:"not_before,omitempty" description:"PBAC: policy is inactive before this RFC3339 instant"`
NotAfter *time.Time `json:"not_after,omitempty" description:"PBAC: policy is inactive after this RFC3339 instant"`
Obligations []string `json:"obligations,omitempty" description:"PBAC: named side-effect actions emitted on match"`
Subjects []policy.SubjectMatch `json:"subjects,omitempty" description:"Subject matchers"`
Actions []string `json:"actions,omitempty" description:"Action patterns"`
Resources []string `json:"resources,omitempty" description:"Resource patterns"`
Conditions []ConditionInput `json:"conditions,omitempty" description:"Policy conditions"`
Metadata map[string]any `json:"metadata,omitempty" description:"Custom metadata"`
}
CreatePolicyRequest is the body for creating an ABAC/PBAC policy.
type CreateResourceTypeRequest ¶
type CreateResourceTypeRequest struct {
Name string `json:"name" description:"Resource type name"`
Description string `json:"description,omitempty" description:"Description"`
Relations []RelationDefInput `json:"relations,omitempty" description:"Relation definitions"`
Permissions []PermissionDefInput `json:"permissions,omitempty" description:"Permission definitions"`
Metadata map[string]any `json:"metadata,omitempty" description:"Custom metadata"`
}
CreateResourceTypeRequest is the body for creating a resource type.
type CreateRoleRequest ¶
type CreateRoleRequest struct {
Name string `json:"name" description:"Role name"`
Slug string `json:"slug" description:"URL-safe slug, unique per (tenant, namespace)"`
NamespacePath string `json:"namespace_path,omitempty" description:"Namespace path (e.g. \"engineering/platform\"); empty = tenant root"`
Description string `json:"description,omitempty" description:"Human-readable description"`
ParentSlug string `` /* 146-byte string literal not displayed */
MaxMembers int `json:"max_members,omitempty" description:"Maximum members (0 = unlimited)"`
IsDefault bool `json:"is_default,omitempty" description:"Default role flag"`
Metadata map[string]any `json:"metadata,omitempty" description:"Custom metadata"`
}
CreateRoleRequest is the body for creating a role.
type DeleteRelationRequest ¶
type DeleteRelationRequest struct {
NamespacePath string `json:"namespace_path,omitempty" description:"Namespace path of the tuple; empty = tenant root"`
ObjectType string `json:"object_type" description:"Object resource type"`
ObjectID string `json:"object_id" description:"Object identifier"`
Relation string `json:"relation" description:"Relation name"`
SubjectType string `json:"subject_type" description:"Subject resource type"`
SubjectID string `json:"subject_id" description:"Subject identifier"`
// SubjectRelation is part of the key: empty names the direct tuple
// (group:eng), "member" the subject set (group:eng#member).
SubjectRelation string `json:"subject_relation,omitempty" description:"Subject relation; empty names the direct tuple, not every subject relation"`
}
DeleteRelationRequest is the body for deleting a relation tuple.
type DetachPermissionRequest ¶
type DetachPermissionRequest struct {
RoleID string `path:"roleId" description:"Role ID"`
PermissionID string `path:"permissionId" description:"Permission ID (legacy)"`
PermissionName string `query:"permission_name,omitempty" description:"Permission name (alternative to permissionId)"`
PermissionNamespacePath string `query:"permission_namespace_path,omitempty" description:"Namespace path of the permission"`
}
DetachPermissionRequest binds the path for DELETE /roles/:roleId/permissions/:permissionId.
As with attach, accept either the legacy permission ID (path-segment) or the natural-key form (query/body). The natural form is required when the caller knows the permission by name.
type GetAssignmentRequest ¶
type GetAssignmentRequest struct {
AssignmentID string `path:"assignmentId" description:"Assignment ID"`
}
GetAssignmentRequest is the path parameter for getting an assignment.
type GetPermissionRequest ¶
type GetPermissionRequest struct {
PermissionID string `path:"permissionId" description:"Permission ID"`
}
GetPermissionRequest is the path parameter for getting a permission.
type GetPolicyRequest ¶
type GetPolicyRequest struct {
PolicyID string `path:"policyId" description:"Policy ID"`
}
GetPolicyRequest is the path parameter for getting a policy.
type GetResourceTypeRequest ¶
type GetResourceTypeRequest struct {
ResourceTypeID string `path:"resourceTypeId" description:"Resource type ID"`
}
GetResourceTypeRequest is the path parameter.
type GetRoleRequest ¶
type GetRoleRequest struct {
RoleID string `path:"roleId" description:"Role ID"`
}
GetRoleRequest is the path parameter for getting a role.
type ListAssignmentsRequest ¶
type ListAssignmentsRequest struct {
SubjectKind string `query:"subject_kind,omitempty" description:"Filter by subject type"`
SubjectID string `query:"subject_id,omitempty" description:"Filter by subject ID"`
RoleID string `query:"role_id,omitempty" description:"Filter by role ID"`
Limit int `query:"limit,omitempty" description:"Maximum results"`
Offset int `query:"offset,omitempty" description:"Results to skip"`
}
ListAssignmentsRequest holds query parameters.
type ListCheckLogsRequest ¶
type ListCheckLogsRequest struct {
SubjectKind string `query:"subject_kind,omitempty" description:"Filter by subject type"`
SubjectID string `query:"subject_id,omitempty" description:"Filter by subject ID"`
Action string `query:"action,omitempty" description:"Filter by action"`
ResourceType string `query:"resource_type,omitempty" description:"Filter by resource type"`
Decision string `query:"decision,omitempty" description:"Filter by decision"`
After string `query:"after,omitempty" description:"After timestamp (RFC3339)"`
Before string `query:"before,omitempty" description:"Before timestamp (RFC3339)"`
Limit int `query:"limit,omitempty" description:"Maximum results"`
Offset int `query:"offset,omitempty" description:"Results to skip"`
}
ListCheckLogsRequest holds query parameters for querying check logs.
type ListPermissionsRequest ¶
type ListPermissionsRequest struct {
Resource string `query:"resource,omitempty" description:"Filter by resource type"`
Action string `query:"action,omitempty" description:"Filter by action"`
Search string `query:"search,omitempty" description:"Search by name"`
Limit int `query:"limit,omitempty" description:"Maximum results"`
Offset int `query:"offset,omitempty" description:"Results to skip"`
}
ListPermissionsRequest holds query parameters.
type ListPoliciesRequest ¶
type ListPoliciesRequest struct {
Effect string `query:"effect,omitempty" description:"Filter by effect (allow/deny)"`
Active string `query:"active,omitempty" description:"Filter by active status (true/false)"`
Search string `query:"search,omitempty" description:"Search by name"`
Limit int `query:"limit,omitempty" description:"Maximum results"`
Offset int `query:"offset,omitempty" description:"Results to skip"`
}
ListPoliciesRequest holds query parameters.
type ListRelationsRequest ¶
type ListRelationsRequest struct {
ObjectType string `query:"object_type,omitempty" description:"Filter by object type"`
ObjectID string `query:"object_id,omitempty" description:"Filter by object ID"`
Relation string `query:"relation,omitempty" description:"Filter by relation"`
SubjectType string `query:"subject_type,omitempty" description:"Filter by subject type"`
SubjectID string `query:"subject_id,omitempty" description:"Filter by subject ID"`
Limit int `query:"limit,omitempty" description:"Maximum results"`
Offset int `query:"offset,omitempty" description:"Results to skip"`
}
ListRelationsRequest holds query parameters.
type ListResourceTypesRequest ¶
type ListResourceTypesRequest struct {
Search string `query:"search,omitempty" description:"Search by name"`
Limit int `query:"limit,omitempty" description:"Maximum results"`
Offset int `query:"offset,omitempty" description:"Results to skip"`
}
ListResourceTypesRequest holds query parameters.
type ListResponse ¶
type ListResponse[T any] struct { Items []T `json:"items" description:"List of items"` Total int64 `json:"total" description:"Total count"` Limit int `json:"limit" description:"Page size"` Offset int `json:"offset" description:"Page offset"` }
ListResponse wraps a list of items with pagination metadata.
type ListRolesRequest ¶
type ListRolesRequest struct {
Search string `query:"search,omitempty" description:"Search by name"`
Limit int `query:"limit,omitempty" description:"Maximum results (default: 50)"`
Offset int `query:"offset,omitempty" description:"Results to skip"`
}
ListRolesRequest holds query parameters for listing roles.
type ListSubjectRolesRequest ¶
type ListSubjectRolesRequest struct {
SubjectKind string `path:"subjectKind" description:"Subject type"`
SubjectID string `path:"subjectId" description:"Subject ID"`
}
ListSubjectRolesRequest gets roles for a subject.
type MatchInfo ¶
type MatchInfo struct {
Source string `json:"source" description:"Source model (rbac, rebac, abac)"`
RuleID string `json:"rule_id,omitempty" description:"Rule identifier"`
Detail string `json:"detail,omitempty" description:"Match detail"`
}
MatchInfo identifies a matched rule.
type Option ¶ added in v1.7.0
type Option func(*API)
Option configures an API instance.
func AllowAnonymousChecks ¶ added in v1.7.0
func AllowAnonymousChecks() Option
AllowAnonymousChecks lets the three check endpoints (POST /v1/authz/check, /v1/authz/enforce, /v1/authz/batch-check) run without a resolved caller identity. Every other route, including the AuthZEN endpoints, still requires one. Off by default, so an unauthenticated caller gets 401 on every route.
func WithAuthorizer ¶ added in v1.7.0
func WithAuthorizer(fn AuthorizerFunc) Option
WithAuthorizer overrides the API's authorization decision function. Mostly useful for tests and for deployments that want a static policy instead of routing the decision back through the engine.
func WithInsecureAllowUnauthenticatedRoutes ¶ added in v1.7.0
func WithInsecureAllowUnauthenticatedRoutes() Option
WithInsecureAllowUnauthenticatedRoutes disables requireIdentity across every route, not just the three check endpoints. It exists solely for the extension package to pass through when the operator has explicitly set auth.require_identity=false and acknowledged the risk via extension.WithInsecureAllowUnauthenticatedRoutes; it is deliberately not documented as a normal option and should never be reached for by a caller wiring api.New directly.
type PermissionDefInput ¶
type PermissionDefInput struct {
Name string `json:"name" description:"Permission name"`
Expression string `json:"expression" description:"Permission expression"`
}
PermissionDefInput is the input for a permission definition.
type PermissionListResponse ¶
type PermissionListResponse struct {
Body any `json:"permissions" body:"" description:"List of permissions"`
}
PermissionListResponse wraps a list of permissions.
type PolicyListResponse ¶
type PolicyListResponse struct {
Body any `json:"policies" body:"" description:"List of policies"`
}
PolicyListResponse wraps a list of policies.
type RelationDefInput ¶
type RelationDefInput struct {
Name string `json:"name" description:"Relation name"`
AllowedSubjects []string `json:"allowed_subjects" description:"Allowed subject types"`
}
RelationDefInput is the input for a relation definition.
type RelationListResponse ¶
type RelationListResponse struct {
Body any `json:"relations" body:"" description:"List of relations"`
}
RelationListResponse wraps a list of relation tuples.
type ResourceTypeListResponse ¶
type ResourceTypeListResponse struct {
Body any `json:"resource_types" body:"" description:"List of resource types"`
}
ResourceTypeListResponse wraps a list of resource types.
type RoleListResponse ¶
type RoleListResponse struct {
Body any `json:"roles" body:"" description:"List of roles"`
}
RoleListResponse wraps a list of roles.
type SubjectRolesResponse ¶
type SubjectRolesResponse struct {
Body any `json:"role_ids" body:"" description:"List of role IDs"`
}
SubjectRolesResponse wraps a list of role IDs for a subject.
type UpdatePolicyRequest ¶
type UpdatePolicyRequest struct {
PolicyID string `path:"policyId" description:"Policy ID"`
Name string `json:"name,omitempty" description:"Policy name"`
Description string `json:"description,omitempty" description:"Description"`
Effect string `json:"effect,omitempty" description:"Policy effect"`
Priority *int `json:"priority,omitempty" description:"Priority"`
IsActive *bool `json:"is_active,omitempty" description:"Active flag"`
NotBefore *time.Time `json:"not_before,omitempty" description:"PBAC: lower time bound (RFC3339)"`
NotAfter *time.Time `json:"not_after,omitempty" description:"PBAC: upper time bound (RFC3339)"`
Obligations []string `json:"obligations,omitempty" description:"PBAC: named side-effect actions emitted on match"`
Subjects []policy.SubjectMatch `json:"subjects,omitempty" description:"Subject matchers"`
Actions []string `json:"actions,omitempty" description:"Action patterns"`
Resources []string `json:"resources,omitempty" description:"Resource patterns"`
Conditions []ConditionInput `json:"conditions,omitempty" description:"Conditions"`
Metadata map[string]any `json:"metadata,omitempty" description:"Metadata"`
}
UpdatePolicyRequest is the body for updating a policy.
type UpdateRoleRequest ¶
type UpdateRoleRequest struct {
RoleID string `path:"roleId" description:"Role ID"`
Name string `json:"name,omitempty" description:"Role name"`
Description string `json:"description,omitempty" description:"Human-readable description"`
ParentSlug *string `` /* 199-byte string literal not displayed */
MaxMembers *int `json:"max_members,omitempty" description:"Maximum members"`
IsDefault *bool `json:"is_default,omitempty" description:"Default role flag"`
Metadata map[string]any `json:"metadata,omitempty" description:"Custom metadata"`
}
UpdateRoleRequest is the body for updating a role.
ParentSlug uses three-state semantics: nil pointer means "leave unchanged", pointer to empty string means "clear the parent", and pointer to a non-empty slug means "set this parent".
type WriteRelationRequest ¶
type WriteRelationRequest struct {
ObjectType string `json:"object_type" description:"Object resource type"`
ObjectID string `json:"object_id" description:"Object identifier"`
Relation string `json:"relation" description:"Relation name"`
SubjectType string `json:"subject_type" description:"Subject resource type"`
SubjectID string `json:"subject_id" description:"Subject identifier"`
SubjectRelation string `json:"subject_relation,omitempty" description:"Subject relation (for nested relations)"`
}
WriteRelationRequest is the body for writing a relation tuple.