Shopify.Utils.loadCurrentSession returns undefined

artooras
Shopify Partner
20 0 6

I know there's another question with the same title, but I decided to post mine as I couldn't find the solution there...

The problem is that Shopify.Utils.loadCurrentSession returns undefined, and I can't figure out why.

I have quite a standard setup created following the Node + React tutorial. My relevant code is below. In my view I'm sending a GET request on button click...

// pages/index.tsx

import React from 'react'
import {
  Page,
  Button,
  Layout
} from '@shopify/polaris'

const Index = () => {

  const getTheme = () => {
    fetch('/api/themes', {
      method: 'GET'
    })
  }

  return (
    <Page>
      <Layout>
        <Button onClick={getTheme}>Get theme</Button>
      </Layout>
    </Page>
  )
}

export default Index

 ...which I intercept in my /api/:path route on the server

// server.js

require('isomorphic-fetch')
require('dotenv').config()
const Koa = require('koa')
const next = require('next')
const Router = require('koa-router')
const {default: Shopify, ApiVersion} = require('@shopify/shopify-api')
const {default: createShopifyAuth, verifyRequest} = require('@shopify/koa-shopify-auth')

Shopify.Context.initialize({
  IS_EMBEDDED_APP: true,
  API_VERSION: ApiVersion.April21,
  API_KEY: process.env.SHOPIFY_API_KEY,
  API_SECRET_KEY: process.env.SHOPIFY_API_SECRET,
  SCOPES: process.env.SHOPIFY_API_SCOPES.split(','),
  SESSION_STORAGE: new Shopify.Session.MemorySessionStorage(),
  HOST_NAME: process.env.SHOPIFY_APP_URL.replace(/https:\/\//, '')
})

const port = parseInt(process.env.PORT) || 3000
const dev = process.env.NODE_ENV !== 'production'
const app = next({dev})
const handle = app.getRequestHandler()

const ACTIVE_SHOPIFY_SHOPS = {}

app.prepare().then(() => {

  // SERVER 

  const server = new Koa()
  server.keys = [Shopify.Context.API_SECRET_KEY]

  server.use(
    createShopifyAuth({
      afterAuth(ctx) {
        const {shop, scope, accessToken} = ctx.state.shopify
        const {host} = ctx.query
        ACTIVE_SHOPIFY_SHOPS[shop] = scope
        ctx.redirect(`/?shop=${shop}&host=${host}`)
      }
    })
  )

  // ROUTER

  const router = new Router()

  const handleRequest = async ctx => {
    await handle(ctx.req, ctx.res)
    ctx.respond = false
    ctx.res.statusCode = 200
  }

  router.get('/', async ctx => {
    const shop = ctx.query.shop
    if (ACTIVE_SHOPIFY_SHOPS[shop] === undefined) {
      ctx.redirect(`/auth?shop=${shop}`)
    } else {
      await handleRequest(ctx)
    }
  })
  router.get('/api/:path', async ctx => {
    const session = await Shopify.Utils.loadCurrentSession(ctx.req, ctx.res)
    const {shop, accessToken} = session
    const client = new Shopify.Clients.Rest(shop, accessToken)
    const path = ctx.params.path
    const themeId = await client.get({path}).then(themes => themes.body.themes.filter(({role}) => role === 'main')[0].id)
  })
  router.get('(/_next/static/.*)', handleRequest)
  router.get('/_next/webpack-hmr', handleRequest)
  router.get('(.*)', verifyRequest(), handleRequest)
  
  router.post('/graphql', verifyRequest({returnHeader: true}), async ctx => {
    await Shopify.Utils.graphqlProxy(ctx.req, ctx.res)
  })

  server.use(router.allowedMethods())
  server.use(router.routes())

  server.listen(port, () => {
    console.log(`> Ready on http://localhost:${port}`)
  })
})

I get undefined in this line specifically:

const session = await Shopify.Utils.loadCurrentSession(ctx.req, ctx.res)

I would really appreciate any help, I have been stuck on this the second day now...

Replies 3 (3)
mkamalkayani
Shopify Partner
84 8 12

Hi,

 

You have to use authenticated fetch.

import {authenticatedFetch} from '@​shopify/app-bridge-utils'
artooras
Shopify Partner
20 0 6

Thanks for the suggestion. I have tried using authenticatedFetch, but for some reason the session is still undefined...

Here's the client-side code where I call fetch:

import {useEffect, useState} from 'react'
import {useAppBridge} from '@shopify/app-bridge-react'
import {authenticatedFetch} from '@shopify/app-bridge-utils'


const Home = () => {

  const app = useAppBridge()
  const [result, setResult] = useState('')

  useEffect(() => {

    authenticatedFetch(app)('api/graphql', {
      method: 'POST',
      body: `{
        shop {
          primaryDomain {
            url
          }
        }
      }`
    })
    .then(result => result.json())
    .then(result => setResult(result))
    .catch(error => console.error(error))
  }, [])

  return (
    <>
      <h1>HOME</h1>
      <p>{result}</p>
    </>
  )
}

export default Home

 

And here's the server-side api route:

import Shopify from '@shopify/shopify-api'
import {NextApiRequest, NextApiResponse} from 'next'


export default async function(req: NextApiRequest, res: NextApiResponse) {

  const session = await Shopify.Utils.loadCurrentSession(req, res)
  console.log(session)
  const client = new Shopify.Clients.Graphql(session.shop, session.accessToken)
  const body = await client.query(req.body).then(({body}) => body)
  res.status(200).json({body})
}

 

session is still undefined... Which is strange, because if I inspect the req, it does contain an authorization header with `Bearer [token]`

artooras_0-1634042231180.png

I'm a bit lost as to why I'm not able to access the session...

agustinsacco
Shopify Partner
13 0 0

I have the exact same issue, im using axios with the interceptor to add the Authorization header but still in the backend I cannot get the users sessions:

 

 

	router.get(
		"/api/shops",
		verifyRequest({ returnHeader: true }),
		async (ctx, next) => {
			const session = await Shopify.Utils.loadCurrentSession(
				ctx.req,
				ctx.res,
				true
			);
			console.log('session', session)
			return true;
		}
	);