Skip to content

Instantly share code, notes, and snippets.

@ewanharris
Last active September 17, 2024 12:00
Show Gist options
  • Save ewanharris/d6cc7492aa3d3dd0a485199364bef135 to your computer and use it in GitHub Desktop.
Save ewanharris/d6cc7492aa3d3dd0a485199364bef135 to your computer and use it in GitHub Desktop.
Approaches to multi-tenant entitlements in OpenFGA
# In this store we've taken the approach of having a condition that checks the assigned org against the active org that is provided as context on the request
name: Entitlements
model: |
model
schema 1.1
type user
type organization
relations
define member: [user with org_check]
type plan
relations
define subscriber: [organization]
define subscriber_member: member from subscriber
type feature
relations
define associated_plan: [plan]
define can_access: subscriber_member from associated_plan
condition org_check(org: string, active_org: string) {
org == active_org
}
tuples:
# The Enterprise plan grants access to the Draft PRs feature
- user: plan:enterprise
relation: associated_plan
object: feature:draft_prs
# The Team plan grants access to the Draft PRs feature
- user: plan:team
relation: associated_plan
object: feature:draft_prs
# The Enterprise plan grants access to the Issues feature
- user: plan:enterprise
relation: associated_plan
object: feature:issues
# The Free plan grants access to the Issues feature
- user: plan:free
relation: associated_plan
object: feature:issues
# The Team plan grants access to the Issues feature
- user: plan:team
relation: associated_plan
object: feature:issues
# The Enterprise plan grants access to the SSO feature
- user: plan:enterprise
relation: associated_plan
object: feature:sso
# Anne is a member of the Alpha organization
- user: user:anne
relation: member
object: organization:alpha
condition:
name: org_check
context:
org: alpha
# Anne is a member of the Brayer organization
- user: user:anne
relation: member
object: organization:brayer
condition:
name: org_check
context:
org: brayer
# Beth is a member of the Brayer organization
- user: user:beth
relation: member
object: organization:brayer
condition:
name: org_check
context:
org: brayer
# Charles is a member of the Cups organization
- user: user:charles
relation: member
object: organization:cups
condition:
name: org_check
context:
org: cups
# The Cups organization has subscribed to the Enterprise plan
- user: organization:cups
relation: subscriber
object: plan:enterprise
# The Alpha organization has subscribed to the Enterprise plan
- user: organization:alpha
relation: subscriber
object: plan:free
# The Brayer organization has subscribed to the Enterprise plan
- user: organization:brayer
relation: subscriber
object: plan:team
tests:
- name: Test
check:
- user: user:anne
object: feature:issues
assertions:
can_access: true
context:
active_org: alpha
- user: user:anne
object: feature:draft_prs
assertions:
can_access: false
context:
active_org: alpha
- user: user:anne
object: feature:sso
assertions:
can_access: false
context:
active_org: alpha
- user: user:anne
object: feature:issues
assertions:
can_access: true
context:
active_org: brayer
- user: user:anne
object: feature:draft_prs
assertions:
can_access: true
context:
active_org: brayer
- user: user:anne
object: feature:sso
assertions:
can_access: false
context:
active_org: brayer
- user: user:beth
object: feature:issues
assertions:
can_access: true
context:
active_org: brayer
- user: user:beth
object: feature:draft_prs
assertions:
can_access: true
context:
active_org: brayer
- user: user:beth
object: feature:sso
assertions:
can_access: false
context:
active_org: brayer
- user: user:charles
object: feature:issues
assertions:
can_access: true
context:
active_org: cups
- user: user:charles
object: feature:draft_prs
assertions:
can_access: true
context:
active_org: cups
- user: user:charles
object: feature:sso
assertions:
can_access: true
context:
active_org: cups
# In this store we've taken the approach of changing the user string to also encode the organization into the string
name: Entitlements
model: |
model
schema 1.1
type user
type organization
relations
define member: [user]
type plan
relations
define subscriber: [organization]
define subscriber_member: member from subscriber
type feature
relations
define associated_plan: [plan]
define can_access: subscriber_member from associated_plan
tuples:
# The Enterprise plan grants access to the Draft PRs feature
- user: plan:enterprise
relation: associated_plan
object: feature:draft_prs
# The Team plan grants access to the Draft PRs feature
- user: plan:team
relation: associated_plan
object: feature:draft_prs
# The Enterprise plan grants access to the Issues feature
- user: plan:enterprise
relation: associated_plan
object: feature:issues
# The Free plan grants access to the Issues feature
- user: plan:free
relation: associated_plan
object: feature:issues
# The Team plan grants access to the Issues feature
- user: plan:team
relation: associated_plan
object: feature:issues
# The Enterprise plan grants access to the SSO feature
- user: plan:enterprise
relation: associated_plan
object: feature:sso
# Anne is a member of the Alpha organization
- user: user:anne|alpha
relation: member
object: organization:alpha
# Anne is also a member of the Brayer organization
- user: user:anne|brayer
relation: member
object: organization:brayer
# Beth is a member of the Brayer organization
- user: user:beth|brayer
relation: member
object: organization:brayer
# Charles is a member of the Cups organization
- user: user:charles|cups
relation: member
object: organization:cups
# The Cups organization has subscribed to the Enterprise plan
- user: organization:cups
relation: subscriber
object: plan:enterprise
# The Alpha organization has subscribed to the Enterprise plan
- user: organization:alpha
relation: subscriber
object: plan:free
# The Brayer organization has subscribed to the Enterprise plan
- user: organization:brayer
relation: subscriber
object: plan:team
tests:
- name: Test
check:
# Check annes access when in the alpha org
- user: user:anne|alpha
object: feature:issues
assertions:
can_access: true
- user: user:anne|alpha
object: feature:draft_prs
assertions:
can_access: false
- user: user:anne|alpha
object: feature:sso
assertions:
can_access: false
# Check annes access when in the brayer org
- user: user:anne|brayer
object: feature:issues
assertions:
can_access: true
- user: user:anne|brayer
object: feature:draft_prs
assertions:
can_access: true
- user: user:anne|brayer
object: feature:sso
assertions:
can_access: false
- user: user:beth|brayer
object: feature:issues
assertions:
can_access: true
- user: user:beth|brayer
object: feature:draft_prs
assertions:
can_access: true
- user: user:beth|brayer
object: feature:sso
assertions:
can_access: false
- user: user:charles|cups
object: feature:issues
assertions:
can_access: true
- user: user:charles|cups
object: feature:draft_prs
assertions:
can_access: true
- user: user:charles|cups
object: feature:sso
assertions:
can_access: true
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment