Skip to main content

Create Subresource Grant

API Endpoint: POST /admin/resources/{type}/{id}/subresources/{subtype}/{subid}/access-grants

Priority: P1

User Story: As an admin, I want to grant a user access to a specific subresource within a parent resource.

Overview

Create an access grant for a user on a subresource. This allows fine-grained control over nested resources, enabling scenarios like granting access to a specific document within a case without granting access to the entire case.

Scenarios

Scenario 1: Grant READ access to case document

Given:

  • Admin is authenticated with scope access-grants:write
  • Case case_abc123 exists
  • Document doc_xyz456 exists as subresource of case
  • User user_12345 exists
  • User does not have access to document

When:

  • Admin POSTs to /admin/resources/case/case_abc123/subresources/document/doc_xyz456/access-grants:
    {
    "userId": "user_12345",
    "accessLevel": "READ"
    }

Then:

  • Response status is 201 Created
  • Response body contains:
    {
    "id": "grant_xyz789",
    "userId": "user_12345",
    "parentResourceType": "case",
    "parentResourceId": "case_abc123",
    "subresourceType": "document",
    "subresourceId": "doc_xyz456",
    "accessLevel": "READ",
    "grantedBy": "admin_789",
    "grantedAt": "2025-10-19T10:00:00Z",
    "expiresAt": null
    }
  • User can now read the document

Scenario 2: Grant with expiration

Given:

  • Admin is authenticated with scope access-grants:write
  • Parent and subresource exist
  • User exists

When:

  • Admin POSTs with expiration:
    {
    "userId": "user_67890",
    "accessLevel": "WRITE",
    "expiresAt": "2025-12-31T23:59:59Z"
    }

Then:

  • Response status is 201 Created
  • Grant is created with expiration date
  • Access automatically revokes after expiration

Scenario 3: Override parent access

Given:

  • Admin is authenticated with scope access-grants:write
  • User has ADMIN access to parent case
  • Admin wants to restrict access to specific document to READ

When:

  • Admin POSTs READ grant on document:
    {
    "userId": "user_12345",
    "accessLevel": "READ",
    "overrideParent": true
    }

Then:

  • Response status is 201 Created
  • User's effective access to document is READ (not inherited ADMIN)
  • User retains ADMIN on case itself

Scenario 4: Duplicate grant

Given:

  • Admin is authenticated with scope access-grants:write
  • User already has WRITE access to subresource

When:

  • Admin attempts to grant WRITE again:
    {
    "userId": "user_12345",
    "accessLevel": "WRITE"
    }

Then:

  • Response status is 409 Conflict
  • Response body contains:
    {
    "error": "DUPLICATE_GRANT",
    "message": "User 'user_12345' already has WRITE access to subresource 'document:doc_xyz456'"
    }

Scenario 5: Parent resource not found

Given:

  • Admin is authenticated with scope access-grants:write
  • No case with ID case_nonexistent

When:

  • Admin POSTs to non-existent parent

Then:

  • Response status is 404 Not Found
  • Response body contains:
    {
    "error": "NOT_FOUND",
    "message": "Parent resource 'case:case_nonexistent' not found"
    }

Scenario 6: Subresource not found

Given:

  • Admin is authenticated with scope access-grants:write
  • Case exists
  • No document doc_nonexistent in case

When:

  • Admin POSTs to non-existent subresource

Then:

  • Response status is 404 Not Found
  • Response body contains:
    {
    "error": "NOT_FOUND",
    "message": "Subresource 'document:doc_nonexistent' not found in parent 'case:case_abc123'"
    }

Scenario 7: Invalid subresource type

Given:

  • Admin is authenticated with scope access-grants:write

When:

  • Admin POSTs with invalid subtype:
    {
    "userId": "user_12345",
    "accessLevel": "READ"
    }
    To: /admin/resources/case/case_abc123/subresources/invalid_type/sub_123/access-grants

Then:

  • Response status is 400 Bad Request
  • Response body contains:
    {
    "error": "VALIDATION_ERROR",
    "message": "Invalid subresource type 'invalid_type' for parent type 'case'"
    }

Request Specification

Path Parameters

ParameterTypeRequiredDescription
typestringYesParent resource type
idstringYesParent resource identifier
subtypestringYesSubresource type
subidstringYesSubresource identifier

Request Body

FieldTypeRequiredConstraintsDescription
userIdstringYesValid user IDUser to grant access
accessLevelstringYesREAD, WRITE, ADMINLevel of access
expiresAtstringNoISO 8601, future dateOptional expiration timestamp
overrideParentbooleanNoDefault: falseOverride inherited parent permissions
replaceExistingbooleanNoDefault: falseReplace existing grant if any

Validation Rules

RuleDescription
Parent existsParent resource must exist
Subresource existsSubresource must exist within parent
Subtype validSubresource type must be valid for parent type
User uniquenessUser cannot have duplicate grant at same level
Future expirationexpiresAt must be in future if provided
Valid access levelMust be READ, WRITE, or ADMIN

Response Specification

Success Response (201 Created)

{
"id": "grant_xyz789",
"userId": "user_12345",
"parentResourceType": "case",
"parentResourceId": "case_abc123",
"subresourceType": "document",
"subresourceId": "doc_xyz456",
"accessLevel": "READ",
"overrideParent": false,
"grantedBy": "admin_789",
"grantedAt": "2025-10-19T10:00:00Z",
"expiresAt": null
}

Response Fields

FieldTypeDescription
idstringGrant identifier (generated)
userIdstringUser who has access
parentResourceTypestringParent resource type
parentResourceIdstringParent resource identifier
subresourceTypestringSubresource type
subresourceIdstringSubresource identifier
accessLevelstringLevel of access
overrideParentbooleanWhether this overrides parent permissions
grantedBystringAdmin who granted access
grantedAtstringGrant timestamp
expiresAtstring | nullExpiration timestamp

Error Responses

StatusError CodeDescription
400VALIDATION_ERRORInvalid input or subresource type
401UNAUTHORIZEDMissing or invalid auth token
403FORBIDDENMissing access-grants:write scope
404NOT_FOUNDParent or subresource not found
409DUPLICATE_GRANTUser already has access at this level

Requirements Mapping

  • FR-206: Accept POST with parent and subresource identifiers
  • FR-207: Validate parent resource exists
  • FR-208: Validate subresource exists within parent
  • FR-209: Validate subresource type is valid for parent type
  • FR-210: Accept userId and accessLevel in body
  • FR-211: Support optional expiration timestamp
  • FR-212: Support overrideParent flag
  • FR-213: Prevent duplicate grants
  • FR-214: Support replaceExisting to upgrade grants
  • FR-215: Record granting admin
  • FR-216: Return complete grant details
  • FR-217: Require access-grants:write scope

Notes

Grant Inheritance vs Override

Without overrideParent:

  • Subresource grant adds to inherited parent permissions
  • User has higher of parent or subresource access
  • Example: Parent ADMIN + Subresource READ = effective ADMIN

With overrideParent: true:

  • Subresource grant replaces inherited permissions
  • User has exactly subresource access level
  • Example: Parent ADMIN + Subresource READ (override) = effective READ
  • Useful for restricting access to sensitive subresources

Use Cases

Fine-grained subresource access is useful for:

  • Sensitive documents: Restrict access to privileged documents within case
  • Temporary sharing: Grant short-term access to specific document
  • Role separation: Paralegal can see case but not financial documents
  • Client portals: Client access to specific documents only

Access Level Hierarchy

In some systems, access levels are hierarchical:

  • ADMIN > WRITE > READ
  • ADMIN implies WRITE and READ
  • WRITE implies READ

Check your authorization implementation.

Performance Considerations

Subresource grants add complexity to authorization:

  • Must check both parent and subresource grants
  • Must apply inheritance/override logic
  • May require multiple database queries
  • Consider caching effective permissions

Bulk Operations

For granting access to multiple subresources:

  • This endpoint requires one call per subresource
  • Consider bulk endpoint for efficiency
  • Or use parent grant if appropriate