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.