Mike Hudson
03/31/2026, 2:35 PMDevRev
03/31/2026, 2:36 PMMike Hudson
03/31/2026, 2:45 PMtype decision
permission view: // big list of things that might allow view
type delegation
permission view: // big list of things that might allow view
type document
relation linked: decision | delegation
permission view: linked.view
Users get linked to have a view permission through multiple sources. Documents can be linked to delegations OR decisions.
However we have the following two scenarios:
1. User has view permissions on a decision with linked document = user can view document check passes.
2. User has view permissions on a delegation with linked document - user can view document check passes.
However, if I go into the FGA schema and change to this:
type document
relation linked: delegation
So removing the OR on the relationship, then check 2 also passes. I am wondering if this has something to do with the permissions on both being set to view or something. We do use ORs throughout the schema but it is often with differnt relations or permissions on the related item. Obviously happy to provide more details, projects, sample IDs to test on it etc if required.
Thanks!
cc @Kenneth Knoll @Vivek Sharma @ReshmaNick Rodriguez
03/31/2026, 6:52 PMNick Rodriguez
03/31/2026, 10:21 PMrelation linked: delegation. This makes sure we're not dealing with a cached or stale schema.
• Are you using the FGA Cache service? If so, schema changes should trigger a cache purge, but we'd like to rule it out. You can test by pointing your check calls directly at the Descope API (not the cache proxy) and see if results change.
• Does your decision type have any permissions that delegation does not? If so, try checking one of those decision-only permissions via document -> linked.<decision-only-permission> with the narrowed schema. If that check still passes, it would confirm that the engine is traversing the linked target based on stored tuples, ignoring the type constraint in the schema.Vivek Sharma
04/01/2026, 7:33 AMMike Hudson
04/01/2026, 12:56 PMconsole.log('CAN USER VIEW DELEGATION');
const canUserViewDelegation = await descopeClient.management.fga.check([{
resource: delegationId,
resourceType: 'delegation',
relation: 'view',
target: userId,
targetType: 'user'
}]);
console.log(canUserViewDelegation.data);
console.log('IS DOCUMENT LINKED TO DELEGATION');
const isDocumentLinkedToDelegation = await descopeClient.management.fga.check([{
resource: documentId,
resourceType: 'document',
relation: 'linked',
target: delegationId,
targetType: 'delegation'
}]);
console.log(isDocumentLinkedToDelegation.data);
console.log('CAN USER VIEW DOCUMENT');
const canUserViewDocument = await descopeClient.management.fga.check([{
resource: documentId,
resourceType: 'document',
relation: 'view',
target: userId,
targetType: 'user'
}]);
console.log(canUserViewDocument.data);
Schema says:
type document
relation linked: decision | delegation
permission view: linked.view
Result is:
CAN USER VIEW DELEGATION
[
{
allowed: true,
tuple: {
resource: '8e0c637e-fc14-4a79-a4ba-5de9beef0acf',
resourceType: 'delegation',
relation: 'view',
target: 'eeddfe9f-de27-47bc-b250-3233902f51ce',
targetType: 'none'
},
info: { direct: true, path: null }
}
]
IS DOCUMENT LINKED TO DELEGATION
[
{
allowed: true,
tuple: {
resource: '179de61c-aa60-46e5-aad2-5db826cc8633',
resourceType: 'document',
relation: 'linked',
target: '8e0c637e-fc14-4a79-a4ba-5de9beef0acf',
targetType: 'none'
},
info: { direct: true, path: null }
}
]
CAN USER VIEW DOCUMENT
[
{
allowed: false,
tuple: {
resource: '179de61c-aa60-46e5-aad2-5db826cc8633',
resourceType: 'document',
relation: 'view',
target: 'eeddfe9f-de27-47bc-b250-3233902f51ce',
targetType: 'none'
},
info: { direct: false, path: null }
}
]
Remove the decision from the relation:
type document
relation linked: delegation
Retest:
CAN USER VIEW DELEGATION
[
{
allowed: true,
tuple: {
resource: '8e0c637e-fc14-4a79-a4ba-5de9beef0acf',
resourceType: 'delegation',
relation: 'view',
target: 'eeddfe9f-de27-47bc-b250-3233902f51ce',
targetType: 'none'
},
info: { direct: true, path: null }
}
]
IS DOCUMENT LINKED TO DELEGATION
[
{
allowed: true,
tuple: {
resource: '179de61c-aa60-46e5-aad2-5db826cc8633',
resourceType: 'document',
relation: 'linked',
target: '8e0c637e-fc14-4a79-a4ba-5de9beef0acf',
targetType: 'none'
},
info: { direct: true, path: null }
}
]
CAN USER VIEW DOCUMENT
[
{
allowed: true,
tuple: {
resource: '179de61c-aa60-46e5-aad2-5db826cc8633',
resourceType: 'document',
relation: 'view',
target: 'eeddfe9f-de27-47bc-b250-3233902f51ce',
targetType: 'none'
},
info: { direct: false, path: null }
}
]
Now the user can view the document!
Change the relation so decision after the OR instead of before:
type document
relation linked: delegation | decision
Rerun test:
CAN USER VIEW DELEGATION
[
{
allowed: true,
tuple: {
resource: '8e0c637e-fc14-4a79-a4ba-5de9beef0acf',
resourceType: 'delegation',
relation: 'view',
target: 'eeddfe9f-de27-47bc-b250-3233902f51ce',
targetType: 'none'
},
info: { direct: true, path: null }
}
]
IS DOCUMENT LINKED TO DELEGATION
[
{
allowed: true,
tuple: {
resource: '179de61c-aa60-46e5-aad2-5db826cc8633',
resourceType: 'document',
relation: 'linked',
target: '8e0c637e-fc14-4a79-a4ba-5de9beef0acf',
targetType: 'none'
},
info: { direct: true, path: null }
}
]
CAN USER VIEW DOCUMENT
[
{
allowed: true,
tuple: {
resource: '179de61c-aa60-46e5-aad2-5db826cc8633',
resourceType: 'document',
relation: 'view',
target: 'eeddfe9f-de27-47bc-b250-3233902f51ce',
targetType: 'none'
},
info: { direct: false, path: null }
}
]
User can still view document
If i put it back to
relation linked: decision | delegation
Then the CAN USER VIEW DOCUMENT check again returns false.Mike Hudson
04/01/2026, 1:12 PMtype delegation
permission test_permission: view
Just copying the view permission to another name so it is unique
And modifying the document schema to use this new unique permission name instead
type document
relation linked: decision | delegation
permission view: linked.test_permission
And yes - using a unqiue permission name does return the right result (that the user can view the document)
CAN USER VIEW DOCUMENT
[
{
allowed: true,
tuple: {
resource: '179de61c-aa60-46e5-aad2-5db826cc8633',
resourceType: 'document',
relation: 'view',
target: 'eeddfe9f-de27-47bc-b250-3233902f51ce',
targetType: 'none'
},
info: { direct: false, path: null }
}
]
So in final testing I played around with the permission check on document for other variations:
permission view: linked.view | linked.test_permission
OR
permission view: linked.test_permission
User can view document
permission view: linked.view
User cannot view document
So the assumption it is to do with a shared permission name between the two object types is correct.Mike Hudson
04/01/2026, 1:21 PMRELATIONS DUMP 179de61c-aa60-46e5-aad2-5db826cc8633
[
{
resource: '179de61c-aa60-46e5-aad2-5db826cc8633',
relationDefinition: 'owner',
namespace: 'document',
target: 'aefead67-e89b-41c6-ab58-3ebe9efe6b59',
targetNamespace: 'user',
targetSetResource: '',
targetSetRelationDefinition: '',
targetSetRelationDefinitionNamespace: '',
query: null
},
{
resource: '179de61c-aa60-46e5-aad2-5db826cc8633',
relationDefinition: 'parent_tenant',
namespace: 'document',
target: '101e1754-969d-4d65-b42e-e02742243be2',
targetNamespace: 'tenant',
targetSetResource: '',
targetSetRelationDefinition: '',
targetSetRelationDefinitionNamespace: '',
query: null
},
{
resource: '179de61c-aa60-46e5-aad2-5db826cc8633',
relationDefinition: 'linked',
namespace: 'document',
target: '8e0c637e-fc14-4a79-a4ba-5de9beef0acf',
targetNamespace: 'delegation',
targetSetResource: '',
targetSetRelationDefinition: '',
targetSetRelationDefinitionNamespace: '',
query: null
}
]
So at this point in time this document is not linked to any decisions, only delegations
@Vivek Sharma - For your testing me messing with the schema may have removed document links you had to decisions. Apologies!
With this information in hand I have changed the schema such that the permission checks should now pass in our use case by modifying the check on document to:
permission view: linked.view | linked.view_parent_decision
So this should at least allow us to validate correct behaviour now on both object typesVivek Sharma
04/02/2026, 5:15 AM