Unless all of the data you are loading is completely public, your app has some sort of users, accounts and permissions systems. If different users have different permissions in your application, then you need a way to tell the server which user is associated with each request.

Apollo Client comes with a pluggable HTTP network interface that includes several options for authentication.

If your app is browser based and you are using cookies for login and session management with a backend, it’s very easy to tell your network interface to send the cookie along with every request. You just need to pass the credentials option. e.g. { credentials: 'same-origin' } as shown below, if your backend server is the same domain or else { credentials: 'include' } if your backend is a different domain.

1
2
3
4
5
6
7
8
9
10
const networkInterface = createNetworkInterface({
uri: '/graphql',
opts: {
credentials: 'same-origin',
},
});
const client = new ApolloClient({
networkInterface,
});

This option is simply passed through to the fetch polyfill used by the network interface when sending the query.

Note: the backend must also allow credentials from the requested origin. e.g. if using the popular ‘cors’ package from npm in node.js, the following settings would work in tandem with the above apollo client settings,

1
2
3
4
5
6
// enable cors
var corsOptions = {
origin: '<insert uri of front-end domain>',
credentials: true // <-- REQUIRED backend setting
};
app.use(cors(corsOptions));

Another common way to identify yourself when using HTTP is to send along an authorization header. The Apollo network interface has a middleware feature that lets you modify requests before they are sent to the server. It’s easy to add an authorization header to every HTTP request. In this example, we’ll pull the login token from localStorage every time a request is sent:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import { ApolloClient, createNetworkInterface } from 'react-apollo';
const networkInterface = createNetworkInterface({
uri: '/graphql',
});
networkInterface.use([{
applyMiddleware(req, next) {
if (!req.options.headers) {
req.options.headers = {}; // Create the header object if needed.
}
// get the authentication token from local storage if it exists
const token = localStorage.getItem('token');
req.options.headers.authorization = token ? `Bearer ${token}` : null;
next();
}
}]);
const client = new ApolloClient({
networkInterface,
});

The server can use that header to authenticate the user and attach it to the GraphQL execution context, so resolvers can modify their behavior based on a user’s role and permissions.

Reset store on logout

Since Apollo caches all of your query results, it’s important to get rid of them when the login state changes.

The easiest way to ensure that the UI and store state reflects the current user’s permissions is to call client.resetStore() after your login or logout process has completed. This will cause the store to be cleared and all active queries to be refetched. The component has to be wrapped in withApollo higher order component to have direct access to Apolloclient through props.

Another option is to reload the page, which will have a similar effect.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
import { withApollo, graphql, gql } from 'react-apollo';
import ApolloClient from 'apollo-client';
class Profile extends React.Component {
constructor(props) {
super(props);
this.logout = () => {
App.logout() // or whatever else your logout flow is
.then(() =>
props.client.resetStore();
)
.catch(err =>
console.error('Logout failed', err);
);
}
}
render() {
const { loading, currentUser } = this.props;
if (loading) {
return (
<p className="navbar-text navbar-right">
Loading...
</p>
);
} else if (currentUser) {
return (
<span>
<p className="navbar-text navbar-right">
{currentUser.login}
&nbsp;
<button onClick={this.logout}>Log out</button>
</p>
</span>
);
}
return (
<p className="navbar-text navbar-right">
<a href="/login/github">Log in with GitHub</a>
</p>
);
}
}
Profile.propTypes = {
client: React.PropTypes.instanceOf(ApolloClient),
loading: React.PropTypes.bool,
currentUser: React.PropTypes.shape({
login: React.PropTypes.string.isRequired,
}),
};
const PROFILE_QUERY = gql`
query CurrentUserForLayout {
currentUser {
login
avatar_url
}
}
`;
export default withApollo(graphql(PROFILE_QUERY, {
options: { fetchPolicy: 'network-only' },
props: ({ data: { loading, currentUser } }) => ({
loading, currentUser,
}),
})(Profile));
Edit on GitHub