Skip to content

fix(graphql): respect frontend roles in ContentType permission check for anonymous users#35038

Merged
fmontes merged 18 commits intomainfrom
fix/graphql-relationship-field-anonymous-permission
Apr 17, 2026
Merged

fix(graphql): respect frontend roles in ContentType permission check for anonymous users#35038
fmontes merged 18 commits intomainfrom
fix/graphql-relationship-field-anonymous-permission

Conversation

@fmontes
Copy link
Copy Markdown
Member

@fmontes fmontes commented Mar 20, 2026

gql-relationship-field-permissions.mp4

Summary

  • Anonymous GraphQL queries that traverse relationship fields were throwing Internal Server Error even when the content type had CMS Anonymous VIEW permission set
  • The fix catches DotSecurityException from getRelationshipFromField() and returns a DataFetcherResult with a PermissionDeniedGraphQLException in the GraphQL errors array — consistent with how FolderCollectionDataFetcher handles denied subfolders

Root Cause

RelationshipFieldDataFetcher.get() passes the request user to getRelationshipFromField(), which internally calls ContentTypeAPI.find(). ContentTypeAPI is instantiated with respectFrontendRoles=false by default, causing filterUserRoles() in PermissionBitAPIImpl to strip the CMS Anonymous role from the user's role set, making the permission check fail even when CMS Anonymous has READ explicitly set.

Approach

Rather than bypassing the permission check with systemUser(), the fetcher now handles DotSecurityException explicitly and surfaces it as a GraphQL-level error. The anonymous user receives null data for the relationship field plus a PERMISSION_DENIED error in the errors array — the same pattern FolderCollectionDataFetcher uses when a user can't access a subfolder.

{
  "data": { "Blog": { "relatedField": null } },
  "errors": [{ "message": "You do not have permission to access the related content type for field 'relatedField'", "extensions": { "code": "PERMISSION_DENIED" } }]
}

Changes

  • RelationshipFieldDataFetcher.java — catch DotSecurityException from getRelationshipFromField() and return DataFetcherResult with PermissionDeniedGraphQLException
  • RelationshipFieldDataFetcherTest.java — regression test for the permission-granted path + new test for the permission-denied path asserting DataFetcherResult with the correct error type

Fixes #35037

Test plan

  • Anonymous GraphQL query on a relationship field where CMS Anonymous has READ — returns data, no error
  • Anonymous GraphQL query on a relationship field where CMS Anonymous lacks READ — returns null data with PERMISSION_DENIED in errors, no Internal Server Error
  • Authenticated user queries with relationship fields still work
# Should return relationship data without "Internal Server Error"
curl -X POST http://localhost:8080/api/v1/graphql \
  -H "Content-Type: application/json" \
  -d '{"query":"{ search(query: \"+contenttype:Blog +live:true\", limit: 3) { title identifier ... on Blog { urlTitle author { firstName lastName } } } }"}'

🤖 Generated with Claude Code

…for anonymous users

ContentTypeAPIImpl.find() was calling doesUserHavePermission() without
passing respectFrontendRoles, hardcoding it to false. This caused the
CMS Anonymous frontend role to be ignored, throwing a DotSecurityException
when anonymous GraphQL queries traversed relationship fields — even when
the content type had CMS Anonymous VIEW permission explicitly set.

Also fixed both overloads of RelationshipAPIImpl.getRelationshipFromField()
to use getContentTypeAPI(user, true) since this method is called from
frontend/GraphQL contexts where frontend roles must be respected.

Fixes #35037

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@claude
Copy link
Copy Markdown
Contributor

claude Bot commented Mar 20, 2026

Claude finished @fmontes's task in 3m 40s —— View job


Code Review

The behavioral fix is sound: splitting the combined catch (DotDataException | DotSecurityException e) block so that DotSecurityException returns a structured DataFetcherResult instead of a DotRuntimeException (→ 500) is correct and consistent with the FolderCollectionDataFetcher subfolder pattern. A few things worth a second look:


1. Misleading Javadoc in test 1 (lines 102–107)

The Javadoc says the pre-fix failure happened "even when CMS Anonymous had VIEW permission on the related content type." That framing is inaccurate based on the code.

PermissionBitAPIImpl.doesUserHavePermission(ContentType, int, User) (line 817) hardcodes respectFrontendRoles=true, which means the CMS Anonymous role is never stripped in this call path. When CMS Anonymous has READ, getRelationshipFromField succeeds without throwing — it did before the fix too. What the fix actually addresses is the case where CMS Anonymous lacks READ: previously that threw a DotRuntimeException (→ 500), now it returns a structured PERMISSION_DENIED error.

The Javadoc comment should reflect what the fix actually does rather than the misdescribed root cause from the issue.

2. Test 1 is not a regression test for the original bug

Since the 3-arg overload already hardcoded respectFrontendRoles=true, testGet_anonymousUser_withCmsAnonymousReadPermission_shouldNotThrow would pass on the original unpatched code too (no exception was thrown when permission was granted). It's a valid positive-path test, but it doesn't catch a regression introduced by the fix; only test 2 does.

3. Vacuous assertNotNull on getErrors() (line 195)

DataFetcherResult.getErrors() in graphql-java never returns null — it returns the list provided via .error(...) or an empty list. This assertion will always pass regardless of the fix.

// line 195 — this can never fail, assertFalse on isEmpty is the real guard
assertNotNull("Errors list should not be null", dataFetcherResult.getErrors());

4. Missing assertNull on dataFetcherResult.getData() in test 2

The PR description states that the denied case returns null data alongside the PERMISSION_DENIED error. The test doesn't verify that. Given that .data(null) is explicitly set in the fetcher, this is worth asserting:

assertNull("Data should be null when permission is denied", dataFetcherResult.getData());

5. persist(null) in test setup (line 59)

new FieldRelationshipDataGen()
        .parent(parentType)
        .child(childType)
        .persist(null);  // ← non-obvious; readers will wonder why null is passed

A short comment clarifying that FieldRelationshipDataGen ignores the argument (and there's no nextPersisted()) would prevent future confusion here.


The production change in RelationshipFieldDataFetcher.java is clean — nothing wrong there. The test issues above won't cause CI failures but do reduce the reliability of the test as a regression guard.

…ntend roles

Adds regression tests for #35037:
- ContentTypeAPIImplTest: verifies find() respects CMS Anonymous frontend role
  when respectFrontendRoles=true, and still denies access when permission is absent
- RelationshipAPITest: verifies getRelationshipFromField() resolves correctly
  for anonymous users when the content type has CMS Anonymous READ permission

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.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

Fixes anonymous GraphQL relationship traversal failures by ensuring ContentType permission checks can include frontend roles (e.g., CMS Anonymous) when the calling API instance is configured to do so.

Changes:

  • Update ContentTypeAPIImpl.find() to pass the instance’s respectFrontendRoles flag into permission checks.
  • Update both RelationshipAPIImpl.getRelationshipFromField() overloads to build a ContentTypeAPI with respectFrontendRoles=true.
  • Add integration regression tests covering anonymous access scenarios for ContentTypeAPI.find() and relationship resolution.

Reviewed changes

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

File Description
dotCMS/src/main/java/com/dotcms/contenttype/business/ContentTypeAPIImpl.java Makes find() permission enforcement depend on the API instance’s respectFrontendRoles setting.
dotCMS/src/main/java/com/dotmarketing/business/RelationshipAPIImpl.java Forces relationship resolution-from-field to use a ContentTypeAPI configured to respect frontend roles.
dotcms-integration/src/test/java/com/dotcms/contenttype/test/ContentTypeAPIImplTest.java Adds regression coverage for anonymous find() with/without CMS Anonymous READ permission.
dotcms-integration/src/test/java/com/dotcms/contenttype/business/RelationshipAPITest.java Adds regression coverage for anonymous relationship resolution when CMS Anonymous has READ on the parent type.

Comment thread dotCMS/src/main/java/com/dotcms/contenttype/business/ContentTypeAPIImpl.java Outdated
…tionship metadata lookup

The relationship lookup in getRelationshipFromField() is a structural metadata
operation (finding the Relationship record by field definition), not a content
access check. Passing the request user (e.g. anonymous) caused a DotSecurityException
when the user's ContentType permission check ran without frontend roles being considered.

The fix uses systemUser() for this lookup — consistent with RelationshipFieldGenerator
which already does the same — while content access is correctly enforced separately
via pullRelatedField() with the original request user.

Also reverts the overly broad changes to ContentTypeAPIImpl.find() (the 3-arg
doesUserHavePermission(ContentType) overload already defaults to respectFrontendRoles=true)
and RelationshipAPIImpl (hardcoding true would affect non-GraphQL call sites).

Fixes #35037

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.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

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

…eld fetching

Replaces the systemUser-based test (which provided no regression protection)
with a proper regression test in RelationshipFieldDataFetcherTest that:

- Creates two content types with a relationship field
- Grants CMS Anonymous READ permission on the parent content type
- Invokes RelationshipFieldDataFetcher.get() with an anonymous user context
- Asserts no DotSecurityException is thrown

This test would have failed on the unpatched codebase, directly covering the
regression described in #35037.

Also registers RelationshipFieldDataFetcherTest in MainSuite1b.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.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

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

fmontes and others added 2 commits March 20, 2026 07:23
…herTest

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…dDataFetcherTest

MANY_TO_MANY returns an empty List when no related content exists, not null.
Asserting non-null was misleading and could fail for ONE_TO_ONE cardinality.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.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

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

@github-actions github-actions Bot added Area : Frontend PR changes Angular/TypeScript frontend code Area : SDK PR changes SDK libraries labels Mar 20, 2026
@claude
Copy link
Copy Markdown
Contributor

claude Bot commented Mar 20, 2026

Pull Request Unsafe to Rollback!!!

  • Category: M-3 — REST / GraphQL / Headless API Contract Change
  • Risk Level: 🟡 MEDIUM
  • Why it's unsafe: PageDataFetcher.java previously returned null when a page was not found (GraphQL response: {"data": {"page": null}}, no errors array entry). After this PR, it throws ResourceNotFoundException, which adds a structured error to the GraphQL errors array ({"data": {"page": null}, "errors": [{"message": "Page not found: ...", "extensions": {"code": "NOT_FOUND", "status": 404, ...}}]}). The same PR updates the frontend SDK client (page-api.ts) to parse and depend on this new shape (step 3 in the revised handler checks extensions.code before checking if page is null). If N is rolled back to N-1, consumers who have deployed the updated SDK expecting structured NOT_FOUND errors will fall back to the null-page path — functional but the semantic error code and status they were relying on are gone. This matches the M-3 signal: "Any API change where the Angular/frontend is updated in the same PR to use the new shape."
  • Code that makes it unsafe:
    • dotCMS/src/main/java/com/dotcms/graphql/datafetcher/page/PageDataFetcher.java lines ~160-163: catch (HTMLPageAssetNotFoundException e) changed from return null to throw new ResourceNotFoundException(...)
    • core-web/libs/sdk/client/src/lib/client/page/page-api.ts: Step 3 handler now checks extensions.code (NOT_FOUND, PERMISSION_DENIED) and builds DotErrorPage with status/code fields — depends on the structured error the backend now emits
    • core-web/libs/sdk/types/src/lib/page/public.ts: DotErrorPage constructor signature changed from (message, httpError?, graphql?) to (message, status, code, httpError?, graphql?) — a breaking API change for any direct SDK consumers
  • Alternative (if possible): To make this rollback-safe, ensure the SDK client gracefully handles both the old response (page: null, no extensions.code) and the new response (page: null + structured errors[].extensions.code). The current page-api.ts implementation does fall back to the null-page check (step 4), so practical impact is LOW — however the DotErrorPage constructor signature change is a hard breaking change for any caller constructing it directly.

@fmontes fmontes force-pushed the fix/graphql-relationship-field-anonymous-permission branch from 3a6763d to d9e7ccf Compare March 20, 2026 17:56
@github-actions github-actions Bot removed the Area : Frontend PR changes Angular/TypeScript frontend code label Mar 20, 2026
Copy link
Copy Markdown
Member

@nollymar nollymar left a comment

Choose a reason for hiding this comment

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

I think the actual fix here is to handle the exception instead of bypassing it with the system user

… instead of bypassing with systemUser

Reverts the systemUser workaround in RelationshipFieldDataFetcher.
DotSecurityException from getRelationshipFromField is now caught and
returned as a DataFetcherResult with a PermissionDeniedGraphQLException
error, consistent with the FolderCollectionDataFetcher pattern.
Adds regression test for the permission-denied path.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.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

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

Comment thread dotcms-integration/src/test/java/com/dotcms/MainSuite1b.java Outdated
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

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

@claude
Copy link
Copy Markdown
Contributor

claude Bot commented Apr 16, 2026

Pull Request Unsafe to Rollback!!!

  • Category: M-3 — REST / GraphQL / Headless API Contract Change
  • Risk Level: 🟡 MEDIUM
  • Why it's unsafe: RelationshipFieldDataFetcher.get() previously caught DotSecurityException (together with DotDataException) and re-threw it as DotRuntimeException, which surfaced in GraphQL as an unhandled execution error — typically {"errors": [{"message": "Exception while fetching data (/relatedField) : ..."}]}. After this PR, DotSecurityException is caught separately and returned as a DataFetcherResult carrying null data plus a PermissionDeniedGraphQLException, producing a structured response: {"data": {"...": {"relatedField": null}}, "errors": [{"message": "You do not have permission...", "extensions": {"code": "PERMISSION_DENIED"}}]}. Any client or headless consumer that was handling the old unstructured error shape (e.g., checking for the runtime-exception message) will receive a different structure after N is deployed. If N is rolled back to N-1, clients that updated to parse extensions.code = "PERMISSION_DENIED" will lose that structured signal and fall back to receiving an unhandled runtime exception error message instead.
  • Code that makes it unsafe:
    • dotCMS/src/main/java/com/dotcms/graphql/datafetcher/RelationshipFieldDataFetcher.java lines 48–57: catch (DotSecurityException e) block changed from throw new DotRuntimeException(e) (shared with DotDataException) to returning a DataFetcherResult.newResult().data(null).error(new PermissionDeniedGraphQLException(...)) — the response envelope now includes errors[].extensions.code which did not exist before.
  • Alternative (if possible): This change is a deliberate bug fix (correct behavior) and aligns with the pattern already used by FolderCollectionDataFetcher. The practical rollback risk is low because: (1) the old behavior was broken for users with CMS Anonymous permission (producing 500s), and (2) clients tolerant of the old error shape will still receive an error — just structured differently. To make it fully rollback-safe, document the response-shape change in the release notes so downstream consumers know to handle both extensions.code = "PERMISSION_DENIED" (N) and the legacy unstructured runtime error (N-1) during any rollback window.

@claude
Copy link
Copy Markdown
Contributor

claude Bot commented Apr 16, 2026

Pull Request Unsafe to Rollback!!!

  • Category: M-3 — REST / GraphQL / Headless API Contract Change
  • Risk Level: 🟡 MEDIUM
  • Why it's unsafe: RelationshipFieldDataFetcher.get() previously caught DotSecurityException together with DotDataException and re-threw it as DotRuntimeException, which GraphQL surfaced as an unhandled execution error (typically {"errors": [{"message": "Exception while fetching data (/relatedField) : ..."}]}, no extensions block). After this PR, DotSecurityException is caught separately and returned as a DataFetcherResult carrying null data plus a PermissionDeniedGraphQLException, producing a structured response: {"data": {"...": {"relatedField": null}}, "errors": [{"message": "You do not have permission...", "extensions": {"code": "PERMISSION_DENIED"}}]}. Any headless consumer that was handling the old unstructured runtime exception error shape will receive a different response structure after N is deployed. If N is rolled back to N-1, clients that updated to parse extensions.code = "PERMISSION_DENIED" will lose that structured signal and revert to receiving the legacy unhandled runtime exception error or an Internal Server Error instead.
  • Code that makes it unsafe:
    • dotCMS/src/main/java/com/dotcms/graphql/datafetcher/RelationshipFieldDataFetcher.java lines 48–57: catch (DotSecurityException e) block changed from re-throwing as DotRuntimeException (shared with DotDataException) to returning DataFetcherResult.newResult().data(null).error(new PermissionDeniedGraphQLException(...)) — the response envelope now includes errors[].extensions.code which did not exist before.
  • Alternative (if possible): This change is a deliberate bug fix (correct behavior) and aligns with the pattern already used by FolderCollectionDataFetcher. The practical rollback risk is low because: (1) the old behavior was broken for users with CMS Anonymous permission (producing 500s), and (2) clients tolerant of the old error shape will still receive an error — just structured differently. To make it fully rollback-safe, document the response-shape change in the release notes so downstream consumers know to handle both extensions.code = "PERMISSION_DENIED" (N) and the legacy unstructured runtime error (N-1) during any rollback window.

fmontes and others added 3 commits April 17, 2026 06:23
… relationship fetcher test

A new content type inherits permissions from the system host, which grants
anonymous read by default. The test for the permission-denied path needs
explicit individual permissions (admin-only) to break inheritance and
prevent CMS Anonymous from passing the ContentType.find() check.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…nymous in relationship test

CMS Admin role has editPermissions=false and cannot be used in permission.save().
Instead, create a temporary custom role (editPermissions=true by default via RoleDataGen)
and grant it READ on the restricted content type. This breaks permission inheritance
so anonymous is excluded from individual permissions, triggering DotSecurityException
in getRelationshipFromField() as the test expects.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…aFetcherTest

- Remove conflicting Field import (would not compile alongside graphql.language.Field)
- Use fully-qualified names for com.dotcms.contenttype.model.field.Field references
- Use ContentTypeDataGen.remove() (sync) instead of async ContentTypeAPI.delete()
- Add restrictedContentlet cleanup in finally block
- Fix DataFetcherResult to typed builder (<Object>newResult())
- Correct error message: "relationship metadata" instead of "related content type"
- Update first-test Javadoc to accurately describe the fix mechanism

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@claude
Copy link
Copy Markdown
Contributor

claude Bot commented Apr 17, 2026

Pull Request Unsafe to Rollback!!!

  • Category: M-3 — REST / GraphQL / Headless API Contract Change
  • Risk Level: 🟡 MEDIUM
  • Why it's unsafe: RelationshipFieldDataFetcher.get() previously caught DotSecurityException together with DotDataException and re-threw it as DotRuntimeException, which GraphQL surfaced as an unhandled execution error (typically {"errors": [{"message": "Exception while fetching data (/relatedField) : ..."}]}, no extensions block). After this PR, DotSecurityException is caught separately and returned as a DataFetcherResult carrying null data plus a PermissionDeniedGraphQLException, producing a structured response: {"data": {"...": {"relatedField": null}}, "errors": [{"message": "You do not have permission to access the relationship metadata for field '...'", "extensions": {"code": "PERMISSION_DENIED"}}]}. Any headless consumer that was handling the old unstructured runtime exception error shape will receive a different response structure after N is deployed. If N is rolled back to N-1, clients that updated to parse extensions.code = "PERMISSION_DENIED" will lose that structured signal and revert to receiving the legacy unhandled runtime exception error or an Internal Server Error instead.
  • Code that makes it unsafe:
    • dotCMS/src/main/java/com/dotcms/graphql/datafetcher/RelationshipFieldDataFetcher.java lines 48–57: catch (DotSecurityException e) block changed from re-throwing as DotRuntimeException (shared with DotDataException) to returning DataFetcherResult.<Object>newResult().data(null).error(new PermissionDeniedGraphQLException(...)) — the response envelope now includes errors[].extensions.code which did not exist before.
  • Alternative (if possible): This change is a deliberate bug fix (correct behavior) and aligns with the pattern already used by FolderCollectionDataFetcher. The practical rollback risk is low because: (1) the old behavior was broken for users with CMS Anonymous permission (producing 500s), and (2) clients tolerant of the old error shape will still receive an error — just structured differently. To make it fully rollback-safe, document the response-shape change in the release notes so downstream consumers know to handle both extensions.code = "PERMISSION_DENIED" (N) and the legacy unstructured runtime error (N-1) during any rollback window.

Suite order matters — new test classes must be appended last.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@claude
Copy link
Copy Markdown
Contributor

claude Bot commented Apr 17, 2026

Pull Request Unsafe to Rollback!!!

  • Category: M-3 — REST / GraphQL / Headless API Contract Change
  • Risk Level: 🟡 MEDIUM
  • Why it's unsafe: RelationshipFieldDataFetcher.get() previously caught DotSecurityException together with DotDataException and re-threw it as DotRuntimeException, which GraphQL surfaced as an unhandled execution error (typically {"errors": [{"message": "Exception while fetching data (/relatedField) : ..."}]}, no extensions block). After this PR, DotSecurityException is caught separately and returned as a DataFetcherResult carrying null data plus a PermissionDeniedGraphQLException, producing a structured response: {"data": {"...": {"relatedField": null}}, "errors": [{"message": "You do not have permission to access the relationship metadata for field '...'", "extensions": {"code": "PERMISSION_DENIED"}}]}. Any headless consumer that was handling the old unstructured runtime exception error shape will receive a different response structure after N is deployed. If N is rolled back to N-1, clients that updated to parse extensions.code = "PERMISSION_DENIED" will lose that structured signal and revert to receiving the legacy unhandled runtime exception error or an Internal Server Error instead.
  • Code that makes it unsafe:
    • dotCMS/src/main/java/com/dotcms/graphql/datafetcher/RelationshipFieldDataFetcher.java lines 48–57: catch (DotSecurityException e) block changed from re-throwing as DotRuntimeException (shared with DotDataException) to returning DataFetcherResult.<Object>newResult().data(null).error(new PermissionDeniedGraphQLException(...)) — the response envelope now includes errors[].extensions.code which did not exist before.
  • Alternative (if possible): This change is a deliberate bug fix (correct behavior) and aligns with the pattern already used by FolderCollectionDataFetcher. The practical rollback risk is low because: (1) the old behavior was broken for users with CMS Anonymous permission (producing 500s), and (2) clients tolerant of the old error shape will still receive an error — just structured differently. To make it fully rollback-safe, document the response-shape change in the release notes so downstream consumers know to handle both extensions.code = "PERMISSION_DENIED" (N) and the legacy unstructured runtime error (N-1) during any rollback window.

@fmontes fmontes added this pull request to the merge queue Apr 17, 2026
Merged via the queue into main with commit e9ad208 Apr 17, 2026
49 checks passed
@fmontes fmontes deleted the fix/graphql-relationship-field-anonymous-permission branch April 17, 2026 20:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

GraphQL RelationshipFieldDataFetcher throws permission error for anonymous users despite CMS Anonymous role having READ on content type

3 participants