I'm using Next.js + react-apollo + apollo-server + express for my website. Recently I added cookie authentication and therefore had to enable CORS in the server for cookies auth to work. However I see that apollo client queries result in http 500 status when performed serverside. The same queries when performed clientside successfully resolve. I'm puzzled because I'd actually expect issues to happen on the client side because CORS has more impact there. I'm not sure what is causing the issue, any suggestions will be very welcome!
The error itself i as follows:
ApolloError: Network error: request to https://example.com/graphql/ failed, reason: write EPROTO 140152723232576:error:14094410:SSL routines:ssl3_read_bytes:sslv3 alert handshake failure:../deps/openssl/openssl/ssl/record/rec_layer_s3.c:1544:SSL alert number 40
at new ApolloError (/src/node_modules/apollo-client/bundle.umd.js:92:26)
at /src/node_modules/apollo-client/bundle.umd.js:1588:34
at /src/node_modules/apollo-client/bundle.umd.js:2008:15
at Set.forEach (<anonymous>)
at /src/node_modules/apollo-client/bundle.umd.js:2006:26
at Map.forEach (<anonymous>)
at QueryManager.broadcastQueries (/src/node_modules/apollo-client/bundle.umd.js:2004:20)
at /src/node_modules/apollo-client/bundle.umd.js:1483:29
at processTicksAndRejections (internal/process/task_queues.js:93:5) {
graphQLErrors: [],
networkError: FetchError: request to https://example.com/graphql/ failed, reason: write EPROTO 140152723232576:error:14094410:SSL routines:ssl3_read_bytes:sslv3 alert handshake failure:../deps/openssl/openssl/ssl/record/rec_layer_s3.c:1544:SSL alert number 40
I'm using an SSL certificate supplied by Amazon Cloudfront.
This is my client code:
_app.js
:
class MyApp extends App {
static async getInitialProps({ Component, ctx }) {
let pageProps = {};
if (Component.getInitialProps) {
pageProps = await Component.getInitialProps(ctx);
if (pageProps.errorStatusCode && ctx.res) {
ctx.res.statusCode = pageProps.errorStatusCode;
}
}
return { pageProps };
}
render() { //render... }
}
I have a HOC for page queries:
const withQuery = (Page, query, variables, errorPolicy = 'none') => {
Page.getInitialProps = async ctx => {
const { apolloClient } = ctx;
try {
const { data } = await apolloClient.query({
query,
variables: vars,
errorPolicy
});
return { data };
} catch (error) {
return { errorStatusCode: error.networkError ? '500' : '404' };
}
};
// if (typeof window === 'undefined') { // THIS CODE IS CAUSING THE ISSUE
// return Page;
// }
}
This is how I initiate apollo client:
import withApollo from 'next-with-apollo';
import ApolloClient, { InMemoryCache } from 'apollo-boost';
import { IntrospectionFragmentMatcher } from 'apollo-cache-inmemory';
import introspectionQueryResultData from '../../fragmentTypes.json';
const fragmentMatcher = new IntrospectionFragmentMatcher({
introspectionQueryResultData
});
function createClient({ ctx, headers, initialState }) {
return new ApolloClient({
credentials: 'include',
uri: 'some_graphql_url',
cache: new InMemoryCache({ fragmentMatcher }).restore(initialState || {}),
headers
});
}
export default withApollo(createClient, { getDataFromTree: 'ssr' });
This is my server code:
import cors from 'cors'
const express = require('express')
const { ApolloServer } = require('apollo-server-express')
const { schema } = require('./models')
const server = new ApolloServer({
schema,
})
// required settings to accept cookies
const corsOptions = {
origin: function (origin, callback) {
if (corsWhitelist.indexOf(origin) !== -1 || !origin) {
callback(null, true)
} else {
callback(new Error(`${origin} - not allowed by CORS`))
}
},
credentials: true
}
let app = express()
app.use(cors(corsOptions))
server.applyMiddleware({ app, cors: false })
const serverUrl = `my_server_url`
app.listen({ port }, () => console.log(` Server ready at ${serverUrl}`))
To sum up my findings:
- The issue originates when
_app.js
callsawait Component.getInitialProps(ctx)
. getInitialProps
is defined in thewithQuery
HOC where the query is executed byapolloClient.query
method.
Without CORS everything works as well.
EDIT: I noticed that the issue will start happening when headers
option is added to createClient
along with CORS.
EDIT2: the error occurs even without CORS, it's enough that headers
option is added to createClient
which create apollo client.