User Authorization with Next.js and Apollo
Jacob Colborn
Posted on January 19, 2020
What Happened
I have been working on an esports news submission web application for the last 2 months now (with a hearty break during December, so maybe closer to a month). Recently, I completed the article submission component. I mounted this component through a submit article page on the site. After getting the functionality running I wanted to make it so only users could submit an article. And, rather than having them write out the article to only be denied, I thought "why not let them know upfront you have to be logged in to submit an article?"
I started working through this process. My initial idea was to run a current user query within the component to get access to the current user's id. If this didn't return any data then I would know that the user was not logged in. After writing this up I could not find a way to encapsulate the submission Mutation within a user Query. After trying a few different methods everyone returned errors. Taking a step back I saw a solution.
The Solution
Taking that step back I saw a solution on the Next.js page that is used to mount the article submission component. By utilizing the <User>
component, I could wrap the <Submit>
component within the <User>
component's returned data. For further clarity, here is the full <User>
component:
import { Query } from "react-apollo";
import gql from "graphql-tag";
import PropTypes from "prop-types";
const CURRENT_USER_QUERY = gql`
query {
me {
id
email
name
permissions
}
}
`;
const User = props => (
<Query {...props} query={CURRENT_USER_QUERY}>
{payload => props.children(payload)}
</Query>
);
User.propTypes = {
children: PropTypes.func.isRequired
};
export default User;
export { CURRENT_USER_QUERY };
So, if we take that payload
returned from the component we can pass this to the <Submit>
component via a prop. Taking this approach we can change our submit.js
page from
import React, { Component } from "react";
import Submit from "../components/Submit";
const submit = () => <Submit />;
export default submit;
To something that will gather data from the <User>
component.
import React, { Component } from "react";
import { Query } from "react-apollo";
import Submit from "../components/Submit";
import User from "../components/User";
import Signin from "../components/Signin";
const submit = () => <User>{({ data }) => <Submit isLoggedIn={data} />}</User>;
export default submit;
The payload here is then passed to <Submit>
within the isLoggedIn
prop. Taking that prop, we can use some if/else statements to either render the submission form or render a login page, depending on what the current user status is.
render() {
if (this.props.isLoggedIn.me) {
return (
Submission form code here
)
} else {
login form, message, or redirect here
}
}
So, if isLoggedIn.me
exists, then the user is logged in. The me
part of this comes from the CURRENT_USER_QUERY. The query returns id, email, name, permission
. We could use any one of these, including isLoggedIn.me.permission
to make sure they are part of a group authorized to access this, but within the web application, any logged-in user is allowed to submit an article.
The Conclusion
This strategy could be utilized for any level of authorization. If this was an admin form I could take the returned data and look for the permission part of the object (this is defined in the query from <User>
and stored in the database for each user). This particular time, I only look for any data at all. As long as that data exists, the user is logged in. This is another excellent lesson in always taking a step back in what we are doing. I spent longer on this then I should but it was because I tried so many different iterations of how I thought it was supposed to work, rather than taking a few minutes to review my thought process and take a different approach.
Thank you for reading. As always, feel free to leave any comments about the code, my thought process, what I could be doing better, or just saying hey.
Posted on January 19, 2020
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.