Skip to content

feat(authzen): add contextual tuples support#251

Draft
blairdrummond wants to merge 1 commit intoopenfga:mainfrom
blairdrummond:main
Draft

feat(authzen): add contextual tuples support#251
blairdrummond wants to merge 1 commit intoopenfga:mainfrom
blairdrummond:main

Conversation

@blairdrummond
Copy link
Copy Markdown

@blairdrummond blairdrummond commented Mar 31, 2026

I was reading the documentation on Authzen in the OpenFGA docs, and noticed that contextual tuples weren't supported. This is a pretty important feature, so I thought I'd take a look and see if it might be possible to add... I did a bit of prototyping and found this worked ok, but there are certainly trade-offs so just wanted to open up a draft to get thoughts

The gist is that I put consistency preferences and contextual tuples into the context of the authzen request. I modified the proto type so that we could get nice typing here.

message Context {
  // OpenFGA consistency preference for this request
  optional openfga.v1.ConsistencyPreference consistency = 1 [json_name = "openfga.dev/consistency"];

  // Contextual tuples to use for this request
  optional openfga.v1.ContextualTupleKeys tuples = 2 [json_name = "openfga.dev/tuple_keys"];

  // Arbitrary additional context values (time, ip_address, etc.)
  optional google.protobuf.Struct data = 3;
}

...

message EvaluationsItemRequest {
  optional Subject subject = 1;
  optional Resource resource = 2;
  optional Action action = 3;
  optional Context context = 4;     // previously google.protobuf.Struct
}

Unfortunately this has the negative consequence of moving other context data into a data sub-field... While this is kinda a bummer, I also don't think it really violates the spec, which doesn't really prescribe much about the structure of the context data.

Section 5.4 / Context

The Context represents the environment of the access evaluation request.
Context is an object which can be used to express attributes of the environment.
Examples of context attributes can include, but are not limited to:

  • The time of day,
  • Location from which the request was received,
  • Capabilities of the PEP,
  • JSON Schema or JSON-LD definitions for the request.

The benefits of this is it basically brings about parity with the openfga api. You can see the relevant changes to the OpenFGA code-base to incorporate these changes here

blairdrummond/openfga@21dbf1e

Summary by CodeRabbit

  • Breaking Changes

    • Updated context parameter schema across evaluation and search endpoints from generic objects to a typed Context structure.
  • New Features

    • Context type now includes dedicated OpenFGA fields for consistency preferences and contextual tuple keys alongside arbitrary request data.

Copilot AI review requested due to automatic review settings March 31, 2026 19:52
@blairdrummond blairdrummond requested review from a team as code owners March 31, 2026 19:52
@linux-foundation-easycla
Copy link
Copy Markdown

linux-foundation-easycla bot commented Mar 31, 2026

CLA Not Signed

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 31, 2026

Important

Review skipped

Auto incremental reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 20cbe776-b8ba-4b19-b84e-ffc4ee3e6a3f

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Walkthrough

The pull request introduces a new typed Context message to the AuthZEN service protocol that includes OpenFGA-specific fields (ConsistencyPreference and ContextualTupleKeys) alongside free-form data. All existing request/response message context fields are updated from untyped google.protobuf.Struct to use this new Context type across the proto definition, OpenAPI documentation, and validation logic.

Changes

Cohort / File(s) Summary
Proto Definition
authzen/v1/authzen_service.proto
Added new Context message type with OpenFGA-specific fields. Updated context field types in 7 request/response messages from optional google.protobuf.Struct to optional Context.
OpenAPI Schema
docs/openapiv2/apidocs.swagger.json
Added Context definition with typed OpenFGA fields and free-form data object. Updated all request/response context field schemas to reference the new Context definition instead of untyped objects.
Validation Logic
proto/authzen/v1/authzen_service.pb.validate.go
Added validation methods for Context message with support for validating embedded fields. Introduced ContextValidationError and ContextMultiError types for structured error reporting.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title accurately describes the main change: introducing a typed Context message to support contextual tuples in AuthZEN requests, which is the primary objective of the changeset.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Signed-off-by: Blair Drummond <bdrummond@coreweave.com>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds contextual tuples support to the AuthZEN service by introducing a new Context message type that provides typed fields for OpenFGA-specific configuration alongside arbitrary additional context data. Previously, context was represented as an unstructured google.protobuf.Struct, which didn't allow proper type safety for consistency preferences and contextual tuples. The change enables consistency preference and contextual tuple configuration at the API level, bringing parity with the OpenFGA API.

Changes:

  • Added new Context message with three fields: consistency preference, contextual tuples, and arbitrary data
  • Updated all context field references across 7 proto messages to use the new Context type
  • Added required imports for OpenFGA proto dependencies
  • Updated OpenAPI/Swagger documentation to reflect the new Context definition with proper JSON field names

Reviewed changes

Copilot reviewed 3 out of 4 changed files in this pull request and generated no comments.

File Description
authzen/v1/authzen_service.proto Added Context message and updated all context field types from google.protobuf.Struct to Context
proto/authzen/v1/authzen_service.pb.validate.go Generated validation code for the new Context message including ValidateAll and validation error types
docs/openapiv2/apidocs.swagger.json Updated OpenAPI definitions to reference the new Context schema with openfga.dev-prefixed fields for consistency and tuples

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@docs/openapiv2/apidocs.swagger.json`:
- Around line 464-465: The request examples referencing "context" must be
updated to match the typed "Context" definition (symbol: Context) so that
arbitrary keys are stored under context.data rather than as top-level fields on
context; find the example objects used in the endpoints that currently show flat
context structures (examples near the changed refs) and wrap those arbitrary
key/value pairs into a nested data object (context.data = { ... }) while
preserving any explicit Context fields (e.g., locale, userId) at the top-level
of Context; ensure every example that switches "$ref": "#/definitions/Context"
is modified so the example shape conforms to the Context schema (move flat
entries into context.data).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 46cddf99-0b08-46da-ad5c-fa56975858d8

📥 Commits

Reviewing files that changed from the base of the PR and between f153694 and c6f7cd9.

⛔ Files ignored due to path filters (1)
  • proto/authzen/v1/authzen_service.pb.go is excluded by !**/*.pb.go
📒 Files selected for processing (3)
  • authzen/v1/authzen_service.proto
  • docs/openapiv2/apidocs.swagger.json
  • proto/authzen/v1/authzen_service.pb.validate.go

Comment on lines +464 to 465
"$ref": "#/definitions/Context"
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Request examples are now out of sync with the typed Context schema.

Lines 464/559/658/757/857 and 2760/2777 switch context to #/definitions/Context (Line 2618), where arbitrary keys belong under context.data. Several embedded endpoint examples still show flat context objects, which no longer match this schema.

Also applies to: 559-560, 658-659, 757-758, 857-858, 2618-2635, 2760-2761, 2777-2778

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/openapiv2/apidocs.swagger.json` around lines 464 - 465, The request
examples referencing "context" must be updated to match the typed "Context"
definition (symbol: Context) so that arbitrary keys are stored under
context.data rather than as top-level fields on context; find the example
objects used in the endpoints that currently show flat context structures
(examples near the changed refs) and wrap those arbitrary key/value pairs into a
nested data object (context.data = { ... }) while preserving any explicit
Context fields (e.g., locale, userId) at the top-level of Context; ensure every
example that switches "$ref": "#/definitions/Context" is modified so the example
shape conforms to the Context schema (move flat entries into context.data).

@aaguiarz
Copy link
Copy Markdown
Member

Hi @blairdrummond!

Thanks for this! We thought about it when implementing it, but weren't sure if we should.

nother approach we though of was to be able to map certain properties to contextual tuples. For example:

Map the subject department poperty:

{
  "type": "user",
  "id": "alice@example.com",
  "properties": {
    "department": "Sales"
  }
}

to

user: alice@example.com
relation: department
object: department:Sales

But we are making too many assumptions (e.g. relation == object type), and if the relation does not exist, it will fail. We'd need you to add explicit mappings for AuthZEN calls, which increased complexity a lot.

However, the value we see in AuthZEN is mostly being able to use it from infrastructure like API/MCP Gateways or Identity Providers. If add extensions they do not support, not sure if it will work.

Why would you use AuthZEN instead of the OpenFGA API if you are coupling your implementation with OpenFGA?

@blairdrummond
Copy link
Copy Markdown
Author

So a couple reasons... in no particular order...

  1. I'm a big fan of OTel, and am thinking that common specifications around AuthZen will make semantic conventions for the authorization decisions easier to standardize. So I'm leaning towards that as an interface to build upon standards there.

  2. While the context is provider-specific, at least the subject/resource/actions syntax is spec-based. It's a bit of a bummer but it reminds me of the way k8s Ingresses required annotations for provider-specific configurations, or in the newer Gateway API the way that they provided extension. The spec's callout of PEP-specific capabilities made me think that this is intended design anyway.

  3. While the contextual tuples themselves are a very openfga specific design, semantically speaking they ARE just context data, and really all the data that gets crammed into the context is going to be policy-engine specific... This data just happens to be typed in a nice way

@aaguiarz
Copy link
Copy Markdown
Member

If you had a specific OTEL component that logged this, how would you handle the contextual tuples? If you need to do something specific, why wouldn't you just have an OTEL component that logs OpenFGA calls? :)

@blairdrummond
Copy link
Copy Markdown
Author

blairdrummond commented Mar 31, 2026

I'm less interested in telemetry regarding the context, except for maybe the size of the context object. I'm more interested in getting telemetry about the subject, action, and resources, as well as knowing which apis (search & access evaluations) are being used. The data in the context I'd probably inspect for purposes of audit logs, but I consider that a different problem / use-case. My main interest in the telemetry is being able to query by subject/action/resource, and that should work the same in a generic way regardless of the authz engine

@aaguiarz
Copy link
Copy Markdown
Member

OK, that makes sense. I'll do some digging on how other AuthZEN products are handling this.

@blairdrummond blairdrummond marked this pull request as draft March 31, 2026 22:19
@blairdrummond
Copy link
Copy Markdown
Author

(Converting to a draft while I go figure out the CLA stuff on my end, but feel free to borrow the idea. The PR is more of an inspiration for an approach rather than something I want merged as is)

@aaguiarz
Copy link
Copy Markdown
Member

aaguiarz commented Apr 1, 2026

Sounds good, and yeah, the hardest part is in the openfga repo :). Not hard though.

@blairdrummond
Copy link
Copy Markdown
Author

Yeah I did actually test those changes here! I wrote an actual functional test in another private repo as well

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants