GraphQL集成Passport认证后Playground无法显示Schema和Docs问题
Let's break down why you're hitting this issue and walk through actionable fixes step by step:
Core Root Causes
Your problem boils down to two key issues:
- You’ve disabled GraphQL introspection with
introspection: falsein your ApolloServer config. Playground relies entirely on introspection queries to generate the Schema and Docs tabs—without this, it can’t fetch schema metadata. - Your global
passport.authenticatemiddleware blocks all requests to/graphql(including Playground’s introspection requests) that lack a valid token, even though introspection shouldn’t require authentication.
Solution 1: Move Authentication to Apollo Context (Recommended)
Instead of applying passport authentication globally to every /graphql request, handle it within Apollo’s context. This lets introspection requests pass through unauthenticated, while still letting you enforce auth only in the resolvers that need it.
Step 1: Update Your ApolloServer Config
Modify your index.ts to shift passport logic into the context, and enable introspection (conditionally for development if you want to keep it disabled in production):
// index.ts import passport from 'passport' import expressPlayground from 'graphql-playground-middleware-express' const app = express() app.use(cors({ origin: true })) app.get('/playground', expressPlayground({ endpoint: '/graphql' })) app.use(passport.initialize()) passport.use(bearerStrategy) // REMOVE the global passport.authenticate middleware block here ;(async () => { await createConnections() const server = await new ApolloServer({ schema: await getSchema(), context: async ({ req }) => { // Handle authentication inside Apollo's context return new Promise((resolve) => { passport.authenticate('oauth-bearer', { session: false }, (err, user) => { resolve({ getUser: () => user, req, }) })(req) }) }, // Enable introspection (allow in dev, disable in production if needed) introspection: process.env.NODE_ENV !== 'production', playground: false, }) server.applyMiddleware({ app, cors: false }) app.listen({ port: ENVIRONMENT.port }, () => { console.log(`Server ready`) }) })()
Step 2: Enforce Auth in Specific Resolvers
Now, in any resolver that requires an authenticated user, check if context.getUser() returns a valid user:
// Example resolver const resolvers = { Query: { protectedUserData: async (_parent, _args, context) => { const user = context.getUser() if (!user) { throw new Error('Authentication required to access this data') } // Fetch and return protected data here } } }
This approach keeps Playground’s schema/docs functional while securing your sensitive resolvers.
Solution 2: Keep Global Authentication but Allow Introspection Requests
If you prefer to retain the global passport middleware, modify it to skip authentication for introspection queries:
// index.ts // Replace your global passport middleware with this app.use((req, res, next) => { // Detect if the request is an introspection query const isIntrospectionQuery = req.path === '/graphql' && req.method === 'POST' && (req.body?.query?.startsWith('query IntrospectionQuery') || req.body?.query?.startsWith('query __schema')); if (isIntrospectionQuery) { // Skip auth for introspection so Playground can fetch schema data return next(); } // Apply authentication for all other GraphQL requests passport.authenticate('oauth-bearer', { session: false })(req, res, next); });
Don’t forget to set introspection: true in your ApolloServer config—this is non-negotiable for Playground to load schema information.
Why Your Previous Attempts Failed
- Switching to the express Playground middleware didn’t fix the issue because your global passport middleware was still blocking introspection requests to
/graphql. - Enabling introspection without adjusting the auth middleware meant those requests were still rejected (since they didn’t include a valid token).
内容的提问来源于stack exchange,提问作者DarkLite1

