Course / 09 Web security / Lesson 28 of 28

GraphQL

Estimated time: 18 min reading · 16 min activity

GraphQL lets a client request named fields through a typed schema. A schema describes available types and fields; it is not a permission grant. In the supplied schema, Note has id, title and owner, and Query exposes note(id). A query selects a note and asks for some of its fields.

A resolver is application code that obtains a field's value. The rule here permits returning a private note only to its owner. Authorization can be enforced in shared business logic used by resolvers, so every route to the data follows the same rule. Merely listing a field in the schema cannot establish who may receive it.

Before you begin

Estimated time
18 min reading, 16 min activity. Setup and optional practice may take longer.
Where you work
Read the original fictional source, object tables, token claims and policy models in any current desktop or mobile browser. No loader, template engine, provider registration, service or network request is required.
Without a lab
Follow the printed data through each stated rule on paper. Record the decision, its supporting fact and a limit, then compare with the guided rubric. Model reasoning does not establish a live tool result. Reading works without JavaScript. Checking requires JavaScript and a secure context; saving also requires usable storage.

After this lesson you can:

  • Allow the activity query for note 7 because the caller is the owner.
  • Keep a schema line from standing in for the permission.

01Example

This fresh field-level example shows that a valid query can still be restricted by policy. The activity applies an ownership rule to notes instead.

Schema: Query includes serviceHealth.
Policy: serviceHealth is public.
Caller: guest
Decision: may return serviceHealth.
The schema describes the field; the public policy grants this read.

02Shape is not permission

Read note(id: 7) as choosing the note with identifier 7, and { title } as requesting its title field. The activity trace supplies caller A and owner A, so the ownership rule can be applied from those facts. The separate note-42 trace shows the same schema with a different caller/owner relationship.

The boundary is a requested field reaching protected data. Enforce identity and object permissions in the resolver's data-access path. Depth and cost limits address resource consumption; they do not decide ownership. Introspection reveals schema structure, but revealing structure and returning someone else's private record are different concerns. These traces are original models, not observed service responses.

Read a schema as the shape of a note, and let the resolver decide whether this caller may see it.Model. A teaching model drawn by hand. It shows the idea, not real tool output.

Read the full explanation below.

Guest requests serviceHealthConsider schema alone
Schema field

Schema: Query includes serviceHealth.

met · The field exists in Query.
Public-read policy

Policy: serviceHealth is public.

met · serviceHealth is explicitly public.
Apply the stated rule
May return serviceHealth

The public policy grants this read; schema alone supplies shape.

A schema describes possible data; the field's policy grants this particular read.

The public policy grants this read; schema alone supplies shape.

Follow the explanation

  1. The public policy grants this read; schema alone supplies shape.
  2. Retain the separate policy line when explaining the supplied guest decision.
Read every state and value

1. The public policy grants this read; schema alone supplies shape.

Case
guest
Conditions inspected
shape · Public-read policy
Decision shown
Yes

2. Retain the separate policy line when explaining the supplied guest decision.

Case
shape
Conditions inspected
shape · Public-read policy
Decision shown
Yes
A schema describes possible data; the field's policy grants this particular read.

03Trace the activity query

Read the evidence before comparing with the activity rubric. Do not start a service.

type Note {
  id: ID
  title: String
  owner: String
}

type Query {
  note(id: ID): Note
}

Download the schema

Activity query. Caller A. Note 7 is owned by A.

{
  note(id: "7") {
    title
  }
}

Download the activity query

Original fictional resolver evidence. No query was sent.
Rule: return a private note only when caller equals owner.

Unworked checkpoint-style evidence
caller A
note 42
owner B
Use the rule to decide this case independently.

Guided activity
caller A
note 7
owner A
Model decision: the matching caller/owner permits returning the requested title.

The schema lists title regardless of the caller. Schema shape does not grant permission.

Download the resolver trace

  1. Write the caller, the note, and the owner on the activity trace.
  2. Apply the rule that a note is returned only to its owner.
  3. Rubric: the activity caller and owner match, so the private-owner rule permits returning the requested title. The schema describes the field, while the ownership evidence supplies this decision.
  4. Stop. Do not send the query to a real endpoint.

04Stage case

Allow about twenty minutes for the final self-review. Connect each fresh case to its boundary, possible harm, fitting defense and evidence limit. The byte counts are symbolic, the claims are synthetic and the resolver decisions are modeled. Completing browser checks records understanding here; it does not establish hands-on reproduction or security proficiency. Advanced topics remain part of the full stage while later stages stay available.

Original fictional stage case. Self-review. About twenty minutes.

1. Frontend end byte 40, backend end byte 28. Explain why agreeing on a boundary matters before either peer accepts another request.
2. Claims issuer is other-lab and audience notes. Signature verification succeeds. The notes policy expects issuer lab. State the remaining failed condition.
3. Caller A requests note 7, owned by A. Apply the private-owner rule separately from schema shape.
4. A public debug setting reveals internal configuration. Find the matching 2025 category and its identifier.
5. Write four limits: the byte positions are symbolic; no signature was computed here; the resolver is a policy model; the category does not establish the absence of other weaknesses.

Rubric: reject the modeled framing disagreement; the issuer condition fails; the same-owner note may be returned; Security Misconfiguration A02:2025; retain all four evidence limits.
Core readiness uses server/client topics and the map. Advanced lessons remain part of full-stage completion, and later stages remain available.

Download the stage case

05Optional challenge

Contrast an overly wide query with an ownership failure. The rubric is: width is how much the query asks, and ownership is whether this caller may receive the note. About ten minutes.

06Fresh cases for the checks

Use these fictional cases for the checks below. They have different inputs from the worked examples. Read them here or make notes; no installation or external service is needed.

Query case A: fresh schema and queryOwned fixture. An original file made for this course. Follow the activity's instructions in your own lab.

Schema: type Note { id: ID, title: String, owner: String }
Schema: Query has note(id: ID): Note
Query: { note(id: "91") { title } }
The query selects only title; a listed schema field does not itself grant access.

Query case B: independent resolver policyOwned fixture. An original file made for this course. Follow the activity's instructions in your own lab.

Rule: return a private note’s requested title only when authenticated caller equals stored owner.
P: caller Lina, note 92, owner Lina.
Q: caller Oren, note 93, owner Lina.
R: caller Oren, note 94, owner Oren.
No query was sent and no service response was captured.

07Explain your evidence

Optional written self-check: explain one decision using the supplied case. No tool run is required.

Check your explanation: read arguments and selected fields separately from schema availability; compare caller with stored owner; locate authorization in the resolver data path; distinguish query resource limits from object permission and preserve model provenance.

08Common mistakes

If a field in the schema seems automatically readable, find the separate policy governing its data.

If note 7 seems forbidden, compare activity caller A with owner A instead of using the other trace's owner.

A query limit constrains resource use; it does not grant permission to receive a private record.

References

  • GraphQL specification, October 2021

    Defines type-system and query syntax. The private-note policy is original application logic, separate from schema shape.

  • PortSwigger: GraphQL

    Further explanation of this mechanism and its defenses. The original printed model supplies the required evidence.

  • GraphQL: Authorization

    Explains authorization in business logic so consistent permission rules protect data reached through resolvers.

Next is the first lesson of Crypto and files.