-
Notifications
You must be signed in to change notification settings - Fork 2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Requiring auth header for introspection queries #1933
Comments
It is not possible at the moment but I'm also looking for something similar. |
@stephenhandley you could use |
@ftatzky I don't follow. I'm familiar with |
@stephenhandley Sorry for the late response. Well
|
@ftatzky ok, understood. the issue there is then that we have the performance overhead of introspection on every session query, regardless of whether they are an internal user (i.e for whom introspection would be appropriate) |
And the reverse is true too. We execute the query even if we can know before that it will fail. Note: In graphql-yoga you can make validation rules that are aware of express' |
I really like @the-noob's suggestion!
|
Hey @stephenhandley, this can be accomplished via the request pipeline. The docs aren't published yet, but you can take a look here: #2008 |
Does anybody know if this is possible today? |
@richardscarrott – As a matter of fact, yes, this is absolutely possible by implementing an
There is helpful Q&A in the ongoing conversation and what's being a [WIP] here is "just" the actual documentation. The respective features do already live in You can see the interface that's being implemented by existing plugins in this file. You can pass plugins to the constructor of Try it out, it's at least pretty straight-forward to play around with, I think... 🔝 I hope these hints might help you out. |
@nether-cat Would this be a valid way of protecting JUST the introspection query? I still want certain unauthorized queries to pass, like a This plugin is currently checking for 3 things:
Am I missing any obvious loopholes? Is there a better way to do this now? NOTE: Invalid authorization headers may pass this check but are caught in my context middleware, where if there is an authorization header, it is validated. const secureIntrospection = {
requestDidStart: ({ request, context }) => {
if (
(request.query.includes('__schema') ||
request.query.includes('__type')) &&
!context.req.get('authorization')
) {
throw new AuthenticationError('GraphQL introspection not authorized!');
}
},
};
const graphQLServer = new ApolloServer({
schema: schemaWithMiddleware,
context: contextMiddleware,
engine: { apiKey: CONFIG.ENGINE_API_KEY },
subscriptions: { path: '/' },
plugins: [secureIntrospection],
introspection: true,
// Development only
playground: CONFIG.IS_DEVELOPMENT,
debug: CONFIG.IS_DEVELOPMENT,
tracing: CONFIG.IS_DEVELOPMENT,
}); |
@danielmahon Thanks for this example! We used something like this in our codebase and released it as a package for usage across our products; referenced this comment in the package. If anyone is interested:- |
We wanted only authenticated backend clients to be able to introspect in production, and the apollo-server-plugin-introspection-auth plugin doesn't really check what we need, so we wrote our own basic plugin for this like @danielmahon mentioned above. Note though that using
|
I noticed a lot of the suggestions here use approaches like regex which could be easily bypassed - and in some cases introduce a security vulnerability. # Fake introspection query to bypass auth
query IntrospectionQuery {
__schema {
__typename
}
}
# Some mutation that no longer requires auth
mutation MaliciousMutation {
deleteThing(id: 1234)
} I've made a gist here which checks that the query is actually an introspection query and not just a query containing introspection. |
@andyrichardson approach is great - but could be better suited to pair with the PluginDefinition callback for |
Cheers @tbrannam yeah you're right! I guess my main point is that the suggestions prior could lead to security vulnerabilities |
@trevor-scheer Buts still not able to understand how to avoid that the Introspection call made from Gateway to federated service to get broken for not having Auth Header. The only way I can bypass that issue is by adding a hardcoded Auth header like:
And this is because during first time call to federated service ('Introspection call') the context is received in willSendRequest params is empty. But this is not a valid solution since the hardcoded token expires and then the pipeline gets broken again and throws error: _An error occurred during Apollo ..... 400: Bad Request. |
It would be nice if the same mechanism that we use to implement Perhaps we could give the @elier-lg In general it is a bad idea if your subgraph servers are directly accessible to end users, so locking down introspection there shouldn't be that relevant. That said, we generally recommend the use of managed federation rather than doing composition inside your graph for production work. |
@andyrichardson Could you clarify how this introduces a security vulnerability? How does the introspection "bypass" authentication? |
Using validation + plugin. import { ApolloServerPlugin, GraphQLRequestListener } from 'apollo-server-plugin-base';
import { GraphQLRequestContext, GraphQLRequest } from 'apollo-server-types';
import { NoSchemaIntrospectionCustomRule, validate } from 'graphql';
const isDevelopment = process.env.NODE_ENV === 'development';
export class ConditionalIntrospectionGraphqlPlugin implements ApolloServerPlugin {
constructor(private checkFn: (request: GraphQLRequest) => boolean) {
}
public async requestDidStart(_requestContext: GraphQLRequestContext<any>): Promise<GraphQLRequestListener> {
return {
didResolveOperation: async (ctx) => {
if (isDevelopment) {
return;
}
if (this.checkFn(_requestContext.request)) {
return;
}
const errors = validate(ctx.schema, ctx.document, [NoSchemaIntrospectionCustomRule]);
if (errors.length) {
throw errors;
}
},
};
}
} Then in apollo server config: // Introspection is controlled by ConditionalIntrospectionGraphqlPlugin
introspection: true,
plugins: [
new ConditionalIntrospectionGraphqlPlugin((request) => {
const key = request.http.headers.get(INTROSPECTION_HEADER);
if (key) {
return key === INTROSPECTION_KEY;
}
}),
], Note, this |
dosent work for me |
If anyone wants a drop-in package for this, I've put something on npm: https://www.npmjs.com/package/apollo-server-plugin-conditional-introspection |
This works for us! Thank you! |
I'm wondering if there's a way to allow introspection queries only when a valid authorization header is passed.
I have introspection disabled outside development, but our client app needs to fetch the schema to be used in code generation for the iOS Apollo client as described here:
https://www.apollographql.com/docs/ios/downloading-schema.html
Currently it looks like I can only enable or disable configuration via a boolean
introspection
option passed in the config to theApolloServer
constructor.I'd like to allow the client developer access to that introspection query if they include a valid internal token in the auth header. Is that possible?
The text was updated successfully, but these errors were encountered: