Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to auth user on server side #2

Closed
shashkovdanil opened this issue Mar 26, 2019 · 2 comments
Closed

How to auth user on server side #2

shashkovdanil opened this issue Mar 26, 2019 · 2 comments

Comments

@shashkovdanil
Copy link

Need analogue https://github.com/zeit/next.js/tree/canary/examples/with-apollo-auth

@jaydenseric jaydenseric transferred this issue from jaydenseric/graphql-react Mar 27, 2019
@jaydenseric
Copy link
Owner

jaydenseric commented Mar 27, 2019

The main challenge is that you need to access the cookie down at the component level, where useGraphQL() is being used, in a universal way as document.cookie is undefined in Node.js during SSR.

What I do, is create and provide a cookie context in pages/_app.js. It is important that the context value is a getCookie() function, and not the value of the cookie itself which can change over time in the browser environment.

import { GraphQLContext } from 'graphql-react'
import { withGraphQLApp } from 'next-graphql-react'
import App, { Container } from 'next/app'
import { CookieContext } from '../components/CookieContext'

class WhimsyApp extends App {
  static async getInitialProps({ ctx, Component }) {
    const props = {}

    if (Component.getInitialProps)
      props.pageProps = await Component.getInitialProps(ctx)

    if (ctx.req) props.cookie = ctx.req.headers.cookie

    return props
  }

  getCookie = () =>
    typeof window === 'undefined' ? this.props.cookie : document.cookie

  render() {
    const { Component, pageProps = {}, graphql } = this.props
    return (
      <Container>
        <GraphQLContext.Provider value={graphql}>
          <CookieContext.Provider value={this.getCookie}>
            <Component {...pageProps} />
          </CookieContext.Provider>
        </GraphQLContext.Provider>
      </Container>
    )
  }
}

export default withGraphQLApp(WhimsyApp)
import { parse } from 'cookie'
import { useGraphQL } from 'graphql-react'
import React from 'react'

export const getViewerTokenFromCookie = cookie => {
  if (!cookie) return null
  // This might be different for your project.
  const { viewer } = parse(cookie)
  return viewer
}

export const whimsyFetchOptionsOverride = getCookie => options => {
  options.url = `${process.env.WHIMSY_API_ORIGIN}${
    process.env.WHIMSY_API_GRAPHQL_PATH
  }`
  const token = getViewerTokenFromCookie(getCookie())
  if (token) options.headers.Authorization = `Bearer ${token}`
}

export const CookieContext = React.createContext()

export const useWhimsyAPI = options => {
  const getCookie = React.useContext(CookieContext)
  return useGraphQL({
    fetchOptionsOverride: whimsyFetchOptionsOverride(getCookie),
    ...options
  })
}

“Whimsy” is the name of my current project. I suggest putting the name of the API the hook is for in the name, so you can potentially have hooks for other APIs. E.g. useGithubAPI, useYelpAPI, etc.

@jaydenseric
Copy link
Owner

The question, it seems, has been answered :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants