User Authorization with Next.js and Apollo
Tags: nextjs, apollo, react, authentication
Published: 2020-01-19 20:08:43

---
title: User Authorization with Next.js and Apollo
published: true
description: Using Apollo, GraphQL, and Next.js to authorize user access
tags: Next.js, Apollo, React, Authentication 
---

## 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:

```javascript
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

```javascript
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.

```javascript
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. 

```javascript
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.