PRE-RELEASE INFORMATION: SUBJECT TO CHANGE

Protocol Documentation

Table of Contents

housecarl_lib/proto/housecarl.proto

CheckAuthorizationRequest

CheckAuthorizationRequest evaluates if an action is allowed

This is the core authorization check that evaluates policies against a request. The request context is a map of string key-value pairs that describe the authorization request.

REQUIRED CONTEXT KEYS:

  • "subject": The entity performing the action (e.g., "user:alice@example.com")
  • "action": The operation being attempted (e.g., "read", "write", "delete")
  • "object": The resource in hc:// URI format (e.g., "hc://550e8400-e29b-41d4-a716-446655440000/documents/report.pdf")

The "object" value MUST be a valid hc:// URI where the domain UUID is used to identify which domain's policies apply. The domain UUID must exist and be accessible by the tenant in the JWT token.

OPTIONAL CONTEXT KEYS:

You can include any additional context attributes that your policies need:

  • "time": Request timestamp (RFC3339 format)
  • "ip_address": Client IP address
  • "user_agent": Client user agent string
  • "owner": Resource owner identifier
  • "department": User's department
  • "clearance_level": Security clearance
  • Any custom application-specific attributes

EVALUATION PROCESS:

  1. Extract domain UUID from object hc:// URI
  2. Retrieve domain and all superior domains
  3. Collect all policies from domain hierarchy
  4. Evaluate each policy against context using policy's engine
  5. Apply invert and deny flags
  6. Return authorized=true if at least one allow and no denies
  7. Return authorized=false if any deny or no allows (default deny)

EXAMPLE REQUEST:

{ "context": { "subject": "user:alice@example.com", "action": "read", "object": "hc://550e8400-e29b-41d4-a716-446655440000/documents/report.pdf", "time": "2024-01-15T10:30:00Z", "ip_address": "192.168.1.100", "owner": "user:alice@example.com" } }

This would match a policy like: { "engine": EVALUATION_ENGINE_PREFIX, "statements": [{ "rules": { "action": "read", "object": "hc://550e8400-e29b-41d4-a716-446655440000/documents/" } }] }

POLICY MACRO EVALUATION:

If policies contain macros (e.g., $current_user()), they are evaluated using information from:

  • JWT token (user_id, tenant_id)
  • Request context (custom attributes)
  • System state (current time, etc.)

For example, a policy with: {"subject": "$current_user()", "owner": "$resource_owner()"} Would expand at evaluation time to: {"subject": "user:alice@example.com", "owner": "user:alice@example.com"} And match if both values are equal.

ERROR CASES:

Returns gRPC error if:

  • Missing required context keys (subject, action, object)
  • Invalid hc:// URI format in object
  • Domain UUID not found or not accessible
  • JWT token invalid or missing
  • Tenant in JWT doesn't match domain's tenant
FieldTypeLabelDescription
contextCheckAuthorizationRequest.ContextEntryrepeatedAuthorization context (key-value pairs, supporting multi-valued attributes)

REQUIRED keys: - subject: Entity performing the action - action: Operation being attempted - object: Resource in hc:// URI format

OPTIONAL keys: - Any custom attributes your policies need (time, ip_address, owner, etc.)

MULTI-VALUE SUPPORT: Each value can be either a single string or an array of strings. Multi-valued attributes use OR semantics during policy matching: A request with group: ["red", "blue"] will match policy statement group: "blue"

Example with single values: { "subject": {"single": "user:alice@example.com"}, "action": {"single": "read"}, "object": {"single": "hc://550e8400.../documents/report.pdf"} }

Example with multi-valued attribute: { "subject": {"single": "user:alice@example.com"}, "action": {"single": "read"}, "object": {"single": "hc://550e8400.../documents/report.pdf"}, "group": {"multiple": {"values": ["red", "blue", "green"]}} } |

CheckAuthorizationRequest.ContextEntry

FieldTypeLabelDescription
keystring
valueRequestValue

CheckAuthorizationResponse

CheckAuthorizationResponse returns the authorization decision

The authorized field indicates whether the request should be allowed.

INTERPRETATION:

authorized = true:

  • At least one policy allowed the request
  • No policies denied the request
  • The action should be permitted

authorized = false:

  • Either no policies matched (default deny)
  • Or at least one policy denied the request (deny overrides allow)
  • The action should be rejected

APPLICATION INTEGRATION:

After receiving the response, your application should:

  1. Check the authorized field
  2. If true, proceed with the requested operation
  3. If false, reject the operation and return 403 Forbidden to the client
  4. Log the authorization decision for audit purposes

PERFORMANCE CONSIDERATIONS:

  • CheckAuthorization calls are designed to be fast (sub-millisecond typical)
  • Results can be cached for short periods (seconds to minutes)
  • Cache keys should include all context attributes used in policies
  • Invalidate cache when policies are updated

AUDIT LOGGING:

All CheckAuthorization calls should be logged to the audit service with:

  • Timestamp
  • Subject (from context)
  • Action (from context)
  • Object (from context)
  • Result (authorized true/false)
  • Tenant ID (from JWT)
  • Request ID (for correlation)
FieldTypeLabelDescription
authorizedboolTrue if the action is allowed, false if denied or no policy matched This is the authorization decision. Application MUST enforce this result. |

ClearUserAttributesRequest

ClearUserAttributesRequest removes all attributes for a user in the current tenant

FieldTypeLabelDescription
user_idstringUUID - User to clear attributes for

CreateApiKeyRequest

FieldTypeLabelDescription
user_idstringUUID - User to create key for

CreateApiKeyResponse

FieldTypeLabelDescription
api_keystringJWT token that can be used for API authentication

CreateDomainRequest

FieldTypeLabelDescription
tenant_idstringUUID - Tenant that will own the domain
namestringDomain name, must be unique within tenant
superior_domain_idsstringrepeatedUUIDs - Parent domains for hierarchy

CreateEmailVerificationTokenRequest

FieldTypeLabelDescription
user_idstringUUID - User the token is for
emailstringEmail address to verify
token_typeTokenTypeType of verification token
expiration_hoursuint32Token validity period (default 24)

CreateEmailVerificationTokenResponse

FieldTypeLabelDescription
tokenstringGenerated verification token (64-char alphanumeric)
expires_atgoogle.protobuf.TimestampToken expiration timestamp

CreateOAuthUserRequest

FieldTypeLabelDescription
usernamestringUsername for the new user
emailstringEmail address
oauth_providerstringOAuth provider (e.g., "google")
oauth_subjectstringProvider's unique user identifier
email_verifiedboolWhether email is pre-verified by OAuth provider
tenant_idstringoptionalOptional tenant to associate user with

CreateOAuthUserResponse

FieldTypeLabelDescription
user_idstringUUID - Created user's identifier

CreateServiceAccountRequest

FieldTypeLabelDescription
namestringService account name (will be prefixed with svc:)
descriptionstringHuman-readable description
tenant_idstringUUID - Tenant to associate with
expiration_daysuint64optionalAPI key expiration (default: 365 days)

CreateServiceAccountResponse

FieldTypeLabelDescription
service_account_idstringUUID - Created service account ID
usernamestringFull username (svc:name)
api_key_idstringUUID - API key ID
emailstringGenerated email (name@service.internal)
expirationint64Unix epoch when API key expires
tokenstringJWT token for immediate authentication (same as Login)

CreateTenantRequest

Request to create a new tenant. See CreateTenant RPC documentation for details on the bootstrap behavior that occurs when a tenant is created (automatic domain, policies, and user association).

FieldTypeLabelDescription
namestringTenant name, must be globally unique across the system. Used for human-readable identification and lookup via GetTenantByName.
descriptionstringHuman-readable description of the tenant's purpose or organization.

CreateTenantUserAssociationRequest

FieldTypeLabelDescription
tenant_idstringUUID - Tenant to grant access to
user_idstringUUID - User to grant access

CreateUserRequest

FieldTypeLabelDescription
usernamestringMust be unique, used for login
emailstringMust be valid email format
passwordstringMust meet security requirements

CreateUserResponse

FieldTypeLabelDescription
user_idstringUUID - Created user's identifier

DeleteApiKeyRequest

FieldTypeLabelDescription
user_idstringUUID - User who owns the key
key_idstringUUID - Key to delete

DeleteDomainRequest

FieldTypeLabelDescription
tenant_idstringUUID - Tenant ID for access control
domain_idstringUUID - Domain to delete

DeleteServiceAccountRequest

FieldTypeLabelDescription
idstringUUID - Service account ID to delete

DeleteTenantRequest

FieldTypeLabelDescription
idstringUUID - Tenant to delete

DeleteTenantUserAssociationRequest

FieldTypeLabelDescription
tenant_idstringUUID - Tenant to revoke access from
user_idstringUUID - User to revoke access

DeleteUserRequest

FieldTypeLabelDescription
idstringUUID - User to delete

Domain

Domain represents a policy container within a tenant Domains can be hierarchical through superior_domain_ids

FieldTypeLabelDescription
idstringUUID - Unique domain identifier
namestringDomain name, unique within tenant
tenant_idstringUUID - Owning tenant
activeboolWhether domain is active for policy evaluation
superior_domain_idsstringrepeatedUUIDs - Parent domains in hierarchy
policiesPolicyrepeatedPolicies attached to this domain

FindUserByOAuthRequest

FieldTypeLabelDescription
oauth_providerstringOAuth provider (e.g., "google")
oauth_subjectstringProvider's unique user identifier

FindUserByOAuthResponse

FieldTypeLabelDescription
user_idstringUUID - User ID if found
foundboolTrue if user exists
usernamestringUsername if found
emailstringEmail if found

GetApiKeyRequest

FieldTypeLabelDescription
user_idstringUUID - User who owns the key
key_idstringUUID - Specific key to retrieve

GetApiKeyResponse

FieldTypeLabelDescription
api_keystringJWT token (metadata only, not the secret)

GetDomainByNameRequest

FieldTypeLabelDescription
tenant_idstringUUID - Tenant ID for access control
namestringDomain name to look up

GetDomainPoliciesRequest

FieldTypeLabelDescription
tenant_idstringUUID - Tenant ID for access control
domain_idstringUUID - Domain whose policies to retrieve

GetDomainPoliciesResponse

FieldTypeLabelDescription
policiesPolicyrepeatedAll policies attached to the domain

GetDomainRequest

FieldTypeLabelDescription
tenant_idstringUUID - Tenant ID for access control
domain_idstringUUID - Domain to retrieve

GetServiceAccountRequest

FieldTypeLabelDescription
idstringUUID - Service account ID

GetTenantAssociationsRequest

FieldTypeLabelDescription
tenant_idstringUUID - Tenant to get associations for

GetTenantAssociationsResponse

FieldTypeLabelDescription
usersUserrepeatedAll users associated with the tenant

GetTenantByNameRequest

FieldTypeLabelDescription
namestringTenant name to look up

GetTenantRequest

FieldTypeLabelDescription
idstringUUID - Tenant identifier

GetTenantUserAssociationRequest

FieldTypeLabelDescription
tenant_idstringUUID - Tenant to check
user_idstringUUID - User to check

GetTenantUserAssociationResponse

FieldTypeLabelDescription
is_associatedboolTrue if user can act on behalf of tenant

GetUserAttributesRequest

GetUserAttributesRequest retrieves all attributes for a user in the current tenant

FieldTypeLabelDescription
user_idstringUUID - User to get attributes for

GetUserAttributesResponse

GetUserAttributesResponse returns all attributes grouped by key

FieldTypeLabelDescription
attributesGetUserAttributesResponse.AttributesEntryrepeatedAll attributes for the user

GetUserAttributesResponse.AttributesEntry

FieldTypeLabelDescription
keystring
valueStringArray

GetUserByNameRequest

FieldTypeLabelDescription
usernamestringUsername to look up

GetUserRequest

FieldTypeLabelDescription
idstringUUID - User to retrieve

IsLoggedInRequest

JWT will be passed in request headers No body needed - authentication via Bearer token

IsLoggedInResponse

FieldTypeLabelDescription
is_logged_inboolTrue if JWT is valid and session active

ListServiceAccountsRequest

FieldTypeLabelDescription
tenant_idstringUUID - Tenant to list accounts for
active_onlybooloptionalFilter to only active accounts (default: false)

ListServiceAccountsResponse

FieldTypeLabelDescription
service_accountsServiceAccountrepeated
total_countuint32Total number of service accounts

ListTenantsRequest

Empty for now, could add pagination later

ListTenantsResponse

FieldTypeLabelDescription
tenantsTenantrepeatedAll tenants in the system

ListUsersRequest

Empty for now, could add pagination later

ListUsersResponse

FieldTypeLabelDescription
usersUserrepeatedAll users in the system

LoginRequest

FieldTypeLabelDescription
usernamestringUsername credential
passwordstringPassword credential
tenantstringoptionalTenant name - for multi-tenant login
durationuint64optionalToken validity duration in seconds

LoginResponse

FieldTypeLabelDescription
tokenstringJWT token for subsequent API calls
user_idstringUUID - Logged in user
tenant_idstringoptionalUUID - Tenant context for the session

LogoutRequest

FieldTypeLabelDescription
user_idstringUUID - Must match JWT claims

MarkEmailVerifiedRequest

FieldTypeLabelDescription
user_idstringUUID - User to mark as verified

Policy

Policy defines authorization rules for resources

A policy is a named set of rules that determine whether a request should be allowed or denied. Policies are attached to domains and evaluated during CheckAuthorization calls.

POLICY EVALUATION:

During CheckAuthorization, each policy is evaluated as follows:

  1. For each statement in the policy: a. Check if all statement keys exist in request context b. Match statement values against context values using the engine c. If all keys match, the statement matches
  2. If ANY statement matches: a. Apply invert flag: if true, flip the result (match→no match, no match→match) b. Track as DENY if deny=true, otherwise as ALLOW c. Continue to next policy
  3. After all policies evaluated: a. If ANY DENY, return authorized=false b. If NO DENY and at least one ALLOW, return authorized=true c. If NO policies matched, return authorized=false (default deny)

POLICY FLAGS:

invert: Reverses the match result

  • Use for "everyone except" scenarios
  • Example: Allow all users except contractors
  • Set invert=true with contractor user pattern

deny: Makes this a deny policy (overrides allows)

  • Use for security boundaries and restrictions
  • Example: Deny all access to /admin/* for non-admins
  • Deny policies always win over allow policies

BEST PRACTICES:

  1. Keep policies simple and focused on a single concern
  2. Use descriptive names that indicate the policy's purpose
  3. Document complex policies in the description field
  4. Prefer simpler engines (FIXED, PREFIX) over complex ones (REGEX)
  5. Use deny policies sparingly for security-critical restrictions
  6. Test policies thoroughly before deployment

POLICY EXAMPLES:

Allow read access to documents: { "name": "read-documents", "description": "Allow users to read documents", "invert": false, "deny": false, "engine": EVALUATION_ENGINE_PREFIX, "statements": [{ "rules": { "action": "read", "object": "hc://550e8400-e29b-41d4-a716-446655440000/documents/" } }] }

Deny access to sensitive resources: { "name": "deny-sensitive", "description": "Prevent access to sensitive resources", "invert": false, "deny": true, "engine": EVALUATION_ENGINE_PREFIX, "statements": [{ "rules": { "object": "hc://550e8400-e29b-41d4-a716-446655440000/sensitive/" } }] }

Allow owner-only access using macros: { "name": "owner-access", "description": "Users can only access resources they own", "invert": false, "deny": false, "engine": EVALUATION_ENGINE_FIXED, "statements": [{ "rules": { "subject": "$current_user()", "owner": "$resource_owner()" } }] }

FieldTypeLabelDescription
namestringPolicy name for identification Must be unique within a domain Used for debugging and audit trails
descriptionstringHuman-readable description Explain the policy's purpose and when it applies Recommended for all policies
invertboolInvert the match result false (default): If statements match, apply allow/deny true: If statements match, do NOT apply (implement "except" logic)
denyboolWhether this is a deny policy false (default): This is an allow policy true: This is a deny policy (overrides all allow policies)
engineEvaluationEngineEvaluation engine for matching rules Determines how statement rules are matched against request context
statementsPolicyStatementrepeatedPolicy statements (rules) A policy matches if ANY statement matches Use multiple statements for OR logic (e.g., allow read OR write)

PolicyStatement

PolicyStatement contains the actual rules to evaluate

A statement is a set of key-value pairs that must ALL match the request context for the statement to match (AND logic).

STATEMENT MATCHING:

For a statement to match:

  1. Every key in rules must exist in the request context
  2. Every value must match according to the policy's engine
  3. Request context may have additional keys (they are ignored)

EXAMPLE:

Policy statement: { "rules": { "action": "read", "object": "hc://550e8400-e29b-41d4-a716-446655440000/documents/" } }

Request context (matches): { "subject": "user:alice@example.com", // ignored (not in rules) "action": "read", // matches "object": "hc://550e8400-e29b-41d4-a716-446655440000/documents/report.pdf" // matches (PREFIX engine) }

Request context (does NOT match): { "action": "write", // does not match (not "read") "object": "hc://550e8400-e29b-41d4-a716-446655440000/documents/report.pdf" }

MULTIPLE STATEMENTS:

Use multiple statements in a policy for OR logic: { "statements": [ {"rules": {"action": "read"}}, {"rules": {"action": "write"}} ] } This matches requests with action="read" OR action="write"

FieldTypeLabelDescription
rulesPolicyStatement.RulesEntryrepeatedEngine-specific rule definitions Keys: Arbitrary context attributes (subject, action, object, time, etc.) Values: Patterns to match (exact, prefix, regex, glob depending on engine)

Common context keys: - subject: The entity performing the action - action: The operation (read, write, delete, etc.) - object: The resource (hc:// URI) - time: Request timestamp - ip_address: Client IP - user_agent: Client user agent - custom_key: Any application-specific attribute |

PolicyStatement.RulesEntry

FieldTypeLabelDescription
keystring
valuestring

PutDomainPoliciesRequest

FieldTypeLabelDescription
tenant_idstringUUID - Tenant ID for access control
domain_idstringUUID - Domain to update policies for
policiesPolicyrepeatedComplete policy set (replaces existing)

RefreshLoginWithTenantRequest

RefreshLoginWithTenantRequest transmutes a tenantless login to a tenantful one

USAGE SCENARIO:

  1. User logs in without tenant parameter → receives JWT with no tenant_id claim
  2. User creates a tenant (becomes associated via CreateTenant)
  3. User calls RefreshLoginWithTenant to upgrade session
  4. Server validates association and issues new JWT with tenant_id claim

SECURITY:

  • Requires valid JWT token in request headers (authentication)
  • Current JWT MUST NOT have a tenant_id claim (can only transmute tenantless → tenantful)
  • Verifies user is associated with requested tenant via TenantsUserLink
  • Returns PERMISSION_DENIED if user is not associated
  • Returns FAILED_PRECONDITION if current JWT already has a tenant

RESPONSE:

Returns LoginResponse with new JWT containing:

  • Same user_id as current JWT
  • tenant_id claim set to requested tenant
  • User attributes for the tenant included in JWT
  • New expiration timestamp (default 12 hours from now)
FieldTypeLabelDescription
tenant_idstringUUID or name of tenant to associate the session with User must already be associated with this tenant

RefreshTenantsRequest

Empty - refreshes tokens for all tenants

RemoveUserAttributeRequest

RemoveUserAttributeRequest removes attribute values for a user in the current tenant

FieldTypeLabelDescription
user_idstringUUID - User to remove attributes from
attribute_keystringAttribute key to modify
attribute_valuesstringrepeatedSpecific values to remove (empty = remove all for key)

RequestValue

RequestValue supports both single and multi-valued context attributes Used in CheckAuthorizationRequest for multi-valued attribute matching

FieldTypeLabelDescription
singlestringSingle string value
multipleStringArrayMultiple values (OR semantics in matching)

ServiceAccount

FieldTypeLabelDescription
idstringUUID - Service account ID
usernamestringFull username (svc:name)
emailstringGenerated email (name@service.internal)
tenant_idstringUUID - Tenant this account is homed to
descriptionstringHuman-readable description
activeboolWhether account is enabled
created_atint64Unix epoch
api_key_idstringUUID - Current API key ID
api_key_expirationint64Unix epoch when API key expires
api_key_activeboolWhether API key is currently valid

SetUserAttributeRequest

SetUserAttributeRequest adds attribute values for a user in the current tenant

FieldTypeLabelDescription
user_idstringUUID - User to set attributes for
attribute_keystringAttribute key (e.g., "group", "role")
attribute_valuesstringrepeatedValues to add (e.g., ["red", "blue"])

StoreOAuthStateRequest

FieldTypeLabelDescription
statestringRandom state string for CSRF protection
tenant_idstringoptionalOptional tenant ID for the OAuth flow
expires_in_minutesint32Expiration time in minutes (default 10)
redirect_uristringOptional redirect URI after OAuth completion
noncestringOptional nonce for additional security

StringArray

StringArray holds multiple string values for a single key

FieldTypeLabelDescription
valuesstringrepeated

Tenant

Tenant represents a top-level organizational unit All resources are isolated by tenant

FieldTypeLabelDescription
idstringUUID - Unique tenant identifier
namestringTenant name, globally unique
descriptionstringHuman-readable description
activeboolWhether tenant is active
control_planeTokensAPI call limits for management operations
data_planeTokensAPI call limits for authorization operations
last_token_resetgoogle.protobuf.TimestampLast token refresh time
subscriptionstringSubscription plan identifier
domainsDomainrepeatedDomains owned by this tenant

Tokens

API call tracking for rate limiting

Housecarl uses a token bucket algorithm for rate limiting based on API calls. Each operation consumes one call, and the call quota is replenished during RefreshTenants operations. "Calls" represents the most technically accurate and user-controllable measure of system usage.

CALL CONSUMPTION:

When an operation is performed:

  1. If available calls >= 1, decrement by 1 and allow the operation
  2. If calls < 1 and overage < max_overage, increment overage and allow
  3. If calls < 1 and overage >= max_overage, reject with RESOURCE_EXHAUSTED

CALL QUOTA REFRESH:

Call RefreshTenants periodically (e.g., hourly, daily) to reset:

  • calls = max_calls (replenish to maximum)
  • overage = 0 (reset burst usage)

RATE LIMIT TYPES:

Tenants have two separate call quotas:

  • control_plane: For management operations (CreateUser, CreateDomain, etc.)
  • data_plane: For authorization checks (CheckAuthorization)

Users have a separate quota:

  • user_plane: For user-initiated operations

BURST CAPACITY:

max_overage allows temporary bursts above max_calls. This is useful for handling traffic spikes without immediately rejecting requests.

Example: max_calls=1000, max_overage=500

  • Steady state: Up to 1000 operations per refresh cycle
  • Burst capacity: Up to 1500 operations (1000 + 500 overage)
  • After burst: Next refresh resets both call quota and overage
FieldTypeLabelDescription
max_tokensint64Maximum calls available per refresh cycle This is your baseline rate limit quota
tokensint64Current available calls (decremented on each operation) When this reaches 0, overage is used
max_overageint64Maximum allowed overage (burst capacity above max_calls) Set to 0 to disable burst capacity
overageint64Current overage usage (incremented when calls reach 0) Reset to 0 during RefreshTenants

UpdateDomainRequest

FieldTypeLabelDescription
tenant_idstringUUID - Must match domain's tenant_id
domainDomainUpdated domain object

UpdateServiceAccountRequest

FieldTypeLabelDescription
idstringUUID - Service account ID
descriptionstringoptionalNew description (if provided)
activebooloptionalNew active status (if provided)

UpdateTenantRequest

FieldTypeLabelDescription
tenantTenantUpdated tenant object, ID must match existing tenant

UpdateUserRequest

FieldTypeLabelDescription
idstringUUID - User to update
usernamestringNew username (must be unique)
emailstringNew email
passwordstringoptionalNew password (optional)
activeboolActive status

User

User represents an authenticated entity that can access tenants

FieldTypeLabelDescription
idstringUUID - Unique user identifier
usernamestringUnique username for login
emailstringEmail address
activeboolWhether user can login
api_key_idsstringrepeatedUUIDs - Associated API keys
user_planeTokensUser-specific API call limits
email_verifiedboolWhether email has been verified

ValidateEmailVerificationTokenRequest

FieldTypeLabelDescription
tokenstringToken to validate
token_typeTokenTypeExpected token type

ValidateEmailVerificationTokenResponse

FieldTypeLabelDescription
validboolTrue if token is valid
user_idstringUUID - User ID associated with token
emailstringEmail address associated with token
error_messagestringError description if invalid (expired, used, not found, etc.)

ValidateOAuthStateRequest

FieldTypeLabelDescription
statestringState string to validate

ValidateOAuthStateResponse

FieldTypeLabelDescription
validboolTrue if state is valid and not expired
tenant_idstringAssociated tenant ID
redirect_uristringAssociated redirect URI (if any)
noncestringAssociated nonce (if any)
error_messagestringError description if invalid

EvaluationEngine

Policy evaluation engine types

The evaluation engine determines how policy statement rules are matched against the request context during authorization checks.

All engines operate on key-value pairs where both keys and values are strings. The request context is matched against policy statement rules according to the selected engine's matching semantics.

MATCHING LOGIC:

For a policy statement to match:

  1. All keys in the policy statement must exist in the request context
  2. The values must match according to the engine's rules
  3. Request context may contain additional keys (they are ignored)

EXAMPLE REQUEST CONTEXT: { "subject": "user:alice@example.com", "action": "read", "object": "hc://550e8400-e29b-41d4-a716-446655440000/documents/report.pdf", "time": "2024-01-15T10:30:00Z", "ip_address": "192.168.1.100" }

NameNumberDescription
EVALUATION_ENGINE_UNSPECIFIED0Unspecified engine - do not use in production policies
EVALUATION_ENGINE_FIXED1FIXED: Exact string match (case-sensitive) Policy statement values must exactly match request context values.

Use for: Precise matching of known values

Example policy statement: { "subject": "user:alice@example.com", "action": "read" }

Matches request context with: subject = "user:alice@example.com" (exact match) action = "read" (exact match)

Does NOT match: subject = "user:alice" (not exact) action = "READ" (case-sensitive) |
EVALUATION_ENGINE_PREFIX2PREFIX: Prefix matching (starts with) Request context values must start with policy statement values.

Use for: Hierarchical resource paths, user groups, action categories

Example policy statement: { "object": "hc://550e8400-e29b-41d4-a716-446655440000/documents/", "action": "read" }

Matches request context with: object = "hc://550e8400-e29b-41d4-a716-446655440000/documents/report.pdf" object = "hc://550e8400-e29b-41d4-a716-446655440000/documents/folder/file.txt"

Does NOT match: object = "hc://550e8400-e29b-41d4-a716-446655440000/images/photo.jpg" |
EVALUATION_ENGINE_REGEX3REGEX: Regular expression matching Policy statement values are regular expressions matched against request context values using Rust regex syntax.

Use for: Complex pattern matching, wildcard domains, time ranges

Example policy statement: { "subject": "^user:[a-z]+@example\.com$", "action": "read|write", "time": "^2024-.T(09|10|11|12|13|14|15|16):." }

Matches request context with: subject = "user:alice@example.com" (matches regex) action = "write" (matches alternation) time = "2024-01-15T14:30:00Z" (matches time range)

WARNING: Complex regex can impact performance. Use PREFIX or GLOB when simpler matching suffices. |
EVALUATION_ENGINE_GLOB4GLOB: Glob pattern matching (shell-style wildcards) Policy statement values use glob patterns (* for any characters, ? for single character) matched against request context values.

Use for: Filename patterns, simple wildcards

Example policy statement: { "object": "hc://550e8400-e29b-41d4-a716-446655440000/documents/.pdf", "subject": "user:@example.com" }

Matches request context with: object = "hc://550e8400-e29b-41d4-a716-446655440000/documents/report.pdf" subject = "user:alice@example.com"

Does NOT match: object = "hc://550e8400-e29b-41d4-a716-446655440000/documents/folder/file.pdf" (glob * does not match path separators by default) |
EVALUATION_ENGINE_FIRST_ORDER_LOGIC5FIRST_ORDER_LOGIC: Complex logical expressions Reserved for future use. Supports complex boolean logic, comparisons, and quantifiers. NOT CURRENTLY IMPLEMENTED |

TokenType

NameNumberDescription
TOKEN_TYPE_UNSPECIFIED0
TOKEN_TYPE_EMAIL_VERIFICATION1
TOKEN_TYPE_PASSWORD_RESET2
TOKEN_TYPE_EMAIL_CHANGE3

HousecarlService

Domain operations Domains are hierarchical policy containers within a tenant

Method NameRequest TypeResponse TypeDescription
CreateDomainCreateDomainRequestDomainCreates a new domain for the specified tenant Domain names must be unique within a tenant and can have superior domains for hierarchy
GetDomainGetDomainRequestDomainRetrieves a domain for the specified tenant Returns error if domain doesn't exist or belongs to different tenant
GetDomainByNameGetDomainByNameRequestDomainRetrieves a domain by name for the specified tenant Returns error if domain doesn't exist or is not unique
UpdateDomainUpdateDomainRequest.google.protobuf.EmptyUpdates an existing domain for the specified tenant ID and tenant_id in request body must match URL parameters
DeleteDomainDeleteDomainRequest.google.protobuf.EmptyDeletes the specified domain Will fail if domain has dependent resources
GetDomainPoliciesGetDomainPoliciesRequestGetDomainPoliciesResponseRetrieves policies for the specified domain Returns the policy list attached to the domain
PutDomainPoliciesPutDomainPoliciesRequest.google.protobuf.EmptyUpdates policies for the specified domain Replaces the entire policy set for the domain
CreateTenantCreateTenantRequestTenantCreates a new tenant with automatic bootstrap configuration.

BOOTSTRAP BEHAVIOR: This operation is a bootstrap operation that any authenticated user can perform. No policy-based authorization check is required beyond valid authentication.

When a tenant is created, the following resources are automatically provisioned in a single atomic transaction: 1. TENANT: The tenant record is created with the provided name and description. 2. USER ASSOCIATION: The creating user is automatically associated with the new tenant via a tenant-user link. This allows the user to operate within the tenant context. 3. ROOT DOMAIN: A domain named "root" is created as the tenant's primary domain. This domain cannot be renamed (enforced by database trigger) and serves as the default policy evaluation context for the tenant.

4. STARTER POLICIES: Two policies are automatically created in the root domain: a) "starter" policy - Grants the creating user full access to all resources within the tenant. This policy matches: - subject (sub claim): the creating user's UUID - action: any (.+) - object: any housecarl resource (hc://.+) b) "root access" policy - Grants the system root user (from the root tenant) administrative access to this tenant. This enables platform-level administration and support operations.

SECURITY CONSIDERATIONS: - The starter policy uses the user's UUID, not username, preventing policy bypass through username changes. - Additional users can be granted access by creating new policies in the root domain or by associating them with the tenant and adding appropriate policy statements. - The creating user should configure appropriate policies before inviting other users to the tenant.

Returns: The created Tenant object with its assigned UUID. |
GetTenantGetTenantRequestTenantRetrieves the specified tenant by ID
GetTenantByNameGetTenantByNameRequestTenantGets a tenant by name Tenant names are unique across the system
UpdateTenantUpdateTenantRequest.google.protobuf.EmptyUpdates an existing tenant ID in request body must match the tenant being updated
DeleteTenantDeleteTenantRequest.google.protobuf.EmptyDeletes the specified tenant Will cascade delete associated resources
ListTenantsListTenantsRequestListTenantsResponseGets all tenants Admin operation that returns all tenants in the system
RefreshTenantsRefreshTenantsRequest.google.protobuf.EmptyRefreshes call quotas for all tenants Should be called every refresh cycle to reset API call limits Updates control_plane, data_plane call quotas, and resets overage counters
CreateUserCreateUserRequestCreateUserResponseCreates a new user Can be called without authentication Username and email must be unique, password must meet security requirements
GetUserGetUserRequestUserGet user by ID
GetUserByNameGetUserByNameRequestUserGet user by name Username lookup across the system
UpdateUserUpdateUserRequestUserUpdates an existing user Can update email, active status, and other metadata
DeleteUserDeleteUserRequest.google.protobuf.EmptyDeletes the specified user Will remove all tenant associations and invalidate tokens
ListUsersListUsersRequestListUsersResponseGet all users Admin operation that returns all users in the system
LoginLoginRequestLoginResponseLog in a user Returns JWT token for subsequent API calls Optional tenant parameter for multi-tenant login
LogoutLogoutRequest.google.protobuf.EmptyLog out a user Invalidates the current JWT token User can only logout their own session
IsLoggedInIsLoggedInRequestIsLoggedInResponseCheck if a user is logged in Validates JWT token and checks if user session is still active
RefreshLoginWithTenantRefreshLoginWithTenantRequestLoginResponseRefresh login with tenant context Transmutes a tenantless login session to a tenantful one Validates current JWT has no tenant, then issues new JWT with tenant_id SECURITY: Verifies user is associated with requested tenant before issuing new token
CreateApiKeyCreateApiKeyRequestCreateApiKeyResponseCreates an API key for the user, associated to the logged-in tenant API keys allow programmatic access without password authentication
GetApiKeyGetApiKeyRequestGetApiKeyResponseGets the API key metadata for the user Returns key information but not the key value itself
DeleteApiKeyDeleteApiKeyRequest.google.protobuf.EmptyDeletes the API key for the user Immediately invalidates the key
CreateServiceAccountCreateServiceAccountRequestCreateServiceAccountResponseCreates a service account within a tenant Admin operation that provisions account + API key Returns API key secret (only shown once!)
ListServiceAccountsListServiceAccountsRequestListServiceAccountsResponseLists all service accounts in a tenant Admin operation
GetServiceAccountGetServiceAccountRequestServiceAccountGets a specific service account by ID Admin operation
UpdateServiceAccountUpdateServiceAccountRequest.google.protobuf.EmptyUpdates a service account (description, active status) Admin operation Cannot update username, email, or tenant_id
DeleteServiceAccountDeleteServiceAccountRequest.google.protobuf.EmptyDeletes a service account Admin operation Cascades to delete associated API keys
SetUserAttributeSetUserAttributeRequest.google.protobuf.EmptySet attribute values for a user in the current tenant Adds the specified values to the user's attributes (upsert semantics) Existing values for the key are preserved; new values are added
RemoveUserAttributeRemoveUserAttributeRequest.google.protobuf.EmptyRemove attribute values from a user in the current tenant If attribute_values is empty, removes ALL values for the key If specific values provided, removes only those values
GetUserAttributesGetUserAttributesRequestGetUserAttributesResponseGet all attributes for a user in the current tenant Returns attributes grouped by key with all values per key
ClearUserAttributesClearUserAttributesRequest.google.protobuf.EmptyClear all attributes for a user in the current tenant Removes every attribute key-value pair for the user
CheckAuthorizationCheckAuthorizationRequestCheckAuthorizationResponseChecks to see if the action is allowed Evaluates request against tenant's policy domains Request must contain "subject", "action", and "object" in context Object is a Resource that follows hc:// URI format
GetTenantAssociationsGetTenantAssociationsRequestGetTenantAssociationsResponseGet users associated with tenant Returns all users that have been granted access to the tenant
GetTenantUserAssociationGetTenantUserAssociationRequestGetTenantUserAssociationResponseGet if tenant is associated for the specified user Returns true if user can act on behalf of the tenant
CreateTenantUserAssociationCreateTenantUserAssociationRequest.google.protobuf.EmptySets tenant to be associated for the specified user Grants user permission to act on behalf of the tenant
DeleteTenantUserAssociationDeleteTenantUserAssociationRequest.google.protobuf.EmptyDeletes tenant - user association Revokes user's permission to act on behalf of the tenant
CreateEmailVerificationTokenCreateEmailVerificationTokenRequestCreateEmailVerificationTokenResponseCreates an email verification token for the specified user Token is valid for the configured expiration period (default 24 hours) Automatically invalidates any existing unused tokens of the same type
ValidateEmailVerificationTokenValidateEmailVerificationTokenRequestValidateEmailVerificationTokenResponseValidates an email verification token Checks expiration, usage status, and token type Marks token as used upon successful validation
MarkEmailVerifiedMarkEmailVerifiedRequest.google.protobuf.EmptyMarks a user's email as verified Called after successful token validation during email verification flow
FindUserByOAuthFindUserByOAuthRequestFindUserByOAuthResponseFinds a user by OAuth provider and subject ID Returns user information if found, error if not found
CreateOAuthUserCreateOAuthUserRequestCreateOAuthUserResponseCreates a new user with OAuth credentials Associates user with specified tenant and marks email as verified
StoreOAuthStateStoreOAuthStateRequest.google.protobuf.EmptyStores OAuth state for CSRF protection during authorization flow State expires after configured period (default 10 minutes)
ValidateOAuthStateValidateOAuthStateRequestValidateOAuthStateResponseValidates OAuth state and retrieves associated information Checks expiration and marks state as used

housecarl_lib/proto/healthz.proto

HealthCheckRequest

FieldTypeLabelDescription
servicestring

HealthCheckResponse

FieldTypeLabelDescription
statusHealthCheckResponse.ServingStatus

HealthCheckResponse.ServingStatus

NameNumberDescription
UNKNOWN0
SERVING1
NOT_SERVING2
SERVICE_UNKNOWN3Used only by the Watch method.

Health

Method NameRequest TypeResponse TypeDescription
CheckHealthCheckRequestHealthCheckResponse
WatchHealthCheckRequestHealthCheckResponse stream

housecarl_lib/proto/jwt.proto

GetPublicKeyRequest

Request to get JWT public key

Empty request - the public key is the same for all callers

GetPublicKeyResponse

Response containing JWT public key information

FieldTypeLabelDescription
public_key_bytesbytesEd25519 public key bytes
algorithmstringAlgorithm type (e.g., "Ed25519")
key_idstringOptional key identifier for key rotation

JwtService

JWT key management service for external service integration Provides public key distribution for JWT token verification

Method NameRequest TypeResponse TypeDescription
GetPublicKeyGetPublicKeyRequestGetPublicKeyResponseGets the public key for JWT verification External services use this to verify JWT tokens issued by Housecarl

Scalar Value Types

.proto TypeNotesC++JavaPythonGoC#PHPRuby
doubledoubledoublefloatfloat64doublefloatFloat
floatfloatfloatfloatfloat32floatfloatFloat
int32Uses variable-length encoding. Inefficient for encoding negative numbers – if your field is likely to have negative values, use sint32 instead.int32intintint32intintegerBignum or Fixnum (as required)
int64Uses variable-length encoding. Inefficient for encoding negative numbers – if your field is likely to have negative values, use sint64 instead.int64longint/longint64longinteger/stringBignum
uint32Uses variable-length encoding.uint32intint/longuint32uintintegerBignum or Fixnum (as required)
uint64Uses variable-length encoding.uint64longint/longuint64ulonginteger/stringBignum or Fixnum (as required)
sint32Uses variable-length encoding. Signed int value. These more efficiently encode negative numbers than regular int32s.int32intintint32intintegerBignum or Fixnum (as required)
sint64Uses variable-length encoding. Signed int value. These more efficiently encode negative numbers than regular int64s.int64longint/longint64longinteger/stringBignum
fixed32Always four bytes. More efficient than uint32 if values are often greater than 2^28.uint32intintuint32uintintegerBignum or Fixnum (as required)
fixed64Always eight bytes. More efficient than uint64 if values are often greater than 2^56.uint64longint/longuint64ulonginteger/stringBignum
sfixed32Always four bytes.int32intintint32intintegerBignum or Fixnum (as required)
sfixed64Always eight bytes.int64longint/longint64longinteger/stringBignum
boolboolbooleanbooleanboolboolbooleanTrueClass/FalseClass
stringA string must always contain UTF-8 encoded or 7-bit ASCII text.stringStringstr/unicodestringstringstringString (UTF-8)
bytesMay contain any arbitrary sequence of bytes.stringByteStringstr[]byteByteStringstringString (ASCII-8BIT)