Background: RedwoodJS Architecture
Cell-Driven Frontend and API-Backed Resolvers
RedwoodJS cleanly separates frontend logic (React Cells) from backend logic (GraphQL resolvers). Each cell queries data via GraphQL, calling resolvers defined in the "/api/src/graphql" and "/api/src/services" directories.
Request Context and Global Session Access
Each API request can carry a context that includes the current user, db instance, logger, and custom headers. The context is built via the getCurrentUser
and context
functions defined in api/src/lib/auth.js
and api/src/functions/graphql.js
.
Diagnosing Context Propagation Issues
Symptoms of Context Breakage
- GraphQL resolvers failing to resolve authenticated user
- Logging shows undefined or empty context values
- App works locally but fails in serverless/staging environments
Use Logging in getCurrentUser
and Resolvers
Log the incoming headers and token claims inside getCurrentUser
to verify context construction:
export const getCurrentUser = async (decoded, { token, type }) => { console.log("Decoded token", decoded) console.log("Token type", type) return { ...decoded, roles: decoded["roles"] || [] } }
Check Middleware and Auth Provider Config
For third-party providers (Auth0, Netlify, Magic.link), ensure the correct Authorization
header is being passed and that serverless environments are forwarding headers properly to GraphQL functions.
Root Causes of Context Misbehavior
Incorrect Lambda Configuration
When deploying to Netlify, Vercel, or AWS Lambda, misconfigured rewrites or missing auth headers in the invocation can prevent getCurrentUser
from being executed correctly.
SSR and GraphQL Race Conditions
With experimental SSR in Redwood, GraphQL calls made during the server-rendering lifecycle may not carry session context unless explicitly hydrated via cookies or headers.
Missing or Stale Auth Implementation
As Redwood apps evolve, it's easy to forget to update api/src/lib/auth.js
to accommodate new claims, scopes, or token structures, especially during provider migrations.
Step-by-Step Fix
Step 1: Verify getCurrentUser Logic
Ensure this method gracefully handles null tokens and logs details for diagnostics.
export const getCurrentUser = async (decoded, context) => { if (!decoded) return null; console.log("Decoded:", decoded) return { ...decoded, roles: decoded["roles"] || [] }; }
Step 2: Validate GraphQL Context Factory
Inspect createGraphQLHandler
call in api/src/functions/graphql.js
to ensure context
and getCurrentUser
are correctly passed in.
export const handler = createGraphQLHandler({ getCurrentUser, context: ({ event, context }) => { return { db, currentUser: context.currentUser }; }, });
Step 3: Check Serverless Provider Logs
Use Netlify/Vercel function logs or AWS Lambda CloudWatch to confirm whether headers are present and if token decoding fails upstream.
Step 4: Add SSR-Aware Token Hydration (if applicable)
Ensure cookies or tokens are available during SSR in web/src/App.js
or a custom provider wrapper.
Best Practices
- Centralize auth token parsing logic and log every assumption
- Use environment-specific GraphQL endpoint tests to simulate real user sessions
- Automate regression tests with mock context objects for isolated resolvers
- Implement circuit-breaker fallbacks for missing context (e.g., anonymous user behavior)
- Version and document context schema as it evolves
Conclusion
Resolver-level bugs in RedwoodJS often trace back to subtle context or auth propagation errors that only surface under real-world conditions. By standardizing context creation, auditing third-party auth integration, and using SSR-aware techniques, teams can avoid brittle behavior and improve app reliability. In complex production systems, these practices help isolate and resolve otherwise opaque issues in a modular and maintainable way.
FAQs
1. Can I test GraphQL resolvers without full auth context?
Yes, you can mock context in service-level tests using Redwood's built-in testing utilities to simulate authenticated and anonymous users.
2. What is the best way to inspect live context in serverless deployments?
Use detailed console logs in getCurrentUser
and deploy with logging enabled in Netlify/Vercel or CloudWatch in AWS Lambda.
3. Does RedwoodJS support multi-tenant context isolation?
Not natively, but custom logic in getCurrentUser
and GraphQL context can be used to simulate tenant scoping based on token claims.
4. Why do some resolvers behave differently between dev and prod?
Differences in token structure, missing headers, or SSR conditions can cause dev/prod discrepancies. Always test in staging environments with production-like settings.
5. How do I handle expired or malformed tokens gracefully?
Always add defensive checks in getCurrentUser
and return null when decoding fails. Avoid throwing unless required for compliance.