DEV Community

Jacob Colborn
Jacob Colborn

Posted on

User Authorization with Next.js and Apollo

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.

Top comments (0)