Solved

Trouble authenticating app proxy request in remix

hacun3jr
Shopify Partner
23 2 17

Hello,

 

I am a Shopify dev newbie, and I am having trouble authenticating the app proxy request coming in from my theme app extension.

 

In my app.new.tsx file i have the following loader function that tries to replicate similarly what the docs say from
https://shopify.dev/docs/api/shopify-app-remix/v1/authenticate/public/app-proxy

loader function is:

export const loader = async ({ request }) => {
  await authenticate.admin(request);
  console.log("hello from loader");
  try {
    const { admin, session, liquid } = await authenticate.public.appProxy(
      request
    );
   
    if (session && session.shop) {
      const titleFromDb = await getBlockTitle();
      console.log("title is: ", titleFromDb);
      return json({ blockTitle: titleFromDb });
    } else {
      return json({ error: "Authentication failed." }, { status: 403 });
    }
  } catch (error) {
    console.error("Error in loader:", error);

    // Check if error is an instance of Error
    if (error instanceof Error) {
      return json({ error: error.message }, { status: 500 });
    } else {
      return json({ error: "An unknown error occurred." }, { status: 500 });
    }
  }
};
And in my theme app extension in the liquid code i have the following code to make the fetch call to the app proxy to communicate with my remix app:
 
<script>
  async function getData() {
    const response = await fetch('/apps/boostbundle');
    const res = await response.json();
    console.log(`---> ${res.content}`);
    getData();
  }
</script>
 
When i try to use it all i keep getting a 404 error and sometimes a 400 error along with a log saying the query does not contain a signature value. I am really confused about how this is all supposed to be set up and I am using ngrok for the tunneling for the app proxy.
 
Error from server log:
 
16:01:06 │ remix │ [shopify-app/INFO] Authenticating admin request
16:01:07 │ remix │ Error in loader: NodeResponse [Response] {
16:01:07 │ remix │ size: 0,
16:01:07 │ remix │ [Symbol(Body internals)]: {
16:01:07 │ remix │ body: null,
16:01:07 │ remix │ type: null,
16:01:07 │ remix │ size: 0,
16:01:07 │ remix │ boundary: null,
16:01:07 │ remix │ disturbed: false,
16:01:07 │ remix │ error: null
16:01:07 │ remix │ },
16:01:07 │ remix │ [Symbol(Response internals)]: {
16:01:07 │ remix │ url: undefined,
16:01:07 │ remix │ status: 400,
16:01:07 │ remix │ statusText: 'Bad Request',
16:01:07 │ remix │ headers: {},
16:01:07 │ remix │ counter: 0,
16:01:07 │ remix │ highWaterMark: undefined
16:01:07 │ remix │ }
16:01:07 │ remix │ }
16:01:09 │ remix │ [shopify-app/INFO] Authenticating app proxy request
16:01:09 │ remix │ [shopify-app/INFO] Query does not contain a signature value.
 
My app proxy config in shopify partners is like this:
 subpath prefix: apps
subpath: boostbundle
 
I have that proxy url set up assuming it's supposed to communicate with my app.new.tsx file
 
Where am i going wrong in all of this. Any help would be greatly appreciated!!
Accepted Solution (1)

Liam
Shopify Staff
2731 302 783

This is an accepted solution.

Hi Hacun3jr,

 

From the error logs and the code you have shared, it seems there could be an issue with how the request is being authenticated. The error Query does not contain a signature value suggests that the request is not being properly signed or the signature is not being included in the request sent from your app to Shopify.

 

When you make a request to your app proxy, Shopify signs the parameters and includes the signature in the request. Your app should then compare this signature with a hash of the parameters to authenticate the request. If the signature is missing or does not match the hash, you will get the Query does not contain a signature value error.

 

Here are a few things you could check or try:

  1. Check how you are generating the signature: Make sure you are correctly generating the signature on your server and including it in the request. The signature should be a hash of your app’s shared secret and the sorted request parameters.

  2. Check your shared secret: Make sure the shared secret you are using to generate the signature is correct. You can find the shared secret in your app settings in the Shopify Partners Dashboard.

  3. Check the request parameters: Ensure that the request parameters you are using to generate the signature match exactly with the parameters Shopify includes in the request. They should be sorted in lexicographical order (alphabetical order).

  4. Check your app proxy configuration: Make sure that the app proxy URL and the subpath you have configured in the Shopify Partners Dashboard matches with the URL and path you are using in your app.

Try the above and let us know if your still seeing issues. 

Liam | Developer Advocate @ Shopify 
 - Was my reply helpful? Click Like to let me know! 
 - Was your question answered? Mark it as an Accepted Solution
 - To learn more visit Shopify.dev or the Shopify Web Design and Development Blog

View solution in original post

Replies 8 (8)

Liam
Shopify Staff
2731 302 783

This is an accepted solution.

Hi Hacun3jr,

 

From the error logs and the code you have shared, it seems there could be an issue with how the request is being authenticated. The error Query does not contain a signature value suggests that the request is not being properly signed or the signature is not being included in the request sent from your app to Shopify.

 

When you make a request to your app proxy, Shopify signs the parameters and includes the signature in the request. Your app should then compare this signature with a hash of the parameters to authenticate the request. If the signature is missing or does not match the hash, you will get the Query does not contain a signature value error.

 

Here are a few things you could check or try:

  1. Check how you are generating the signature: Make sure you are correctly generating the signature on your server and including it in the request. The signature should be a hash of your app’s shared secret and the sorted request parameters.

  2. Check your shared secret: Make sure the shared secret you are using to generate the signature is correct. You can find the shared secret in your app settings in the Shopify Partners Dashboard.

  3. Check the request parameters: Ensure that the request parameters you are using to generate the signature match exactly with the parameters Shopify includes in the request. They should be sorted in lexicographical order (alphabetical order).

  4. Check your app proxy configuration: Make sure that the app proxy URL and the subpath you have configured in the Shopify Partners Dashboard matches with the URL and path you are using in your app.

Try the above and let us know if your still seeing issues. 

Liam | Developer Advocate @ Shopify 
 - Was my reply helpful? Click Like to let me know! 
 - Was your question answered? Mark it as an Accepted Solution
 - To learn more visit Shopify.dev or the Shopify Web Design and Development Blog

CodeCodeCode
Shopify Partner
4 0 1

Can you tell me why I'm getting a 404 error when trying to make a request from my theme app extension

<script>
document.addEventListener('submit'async function(event) {
if (event.target.matches('form[action="/cart/add"]')) {
console.log("Form submitted");
console.log("Form submitted");
const productId = "43565159415939";
const data = { productId };

 

const response = await fetch('/apps/proxy943/', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(data),
});
}
});
</script>
 
Here is my App proxy config
[app_proxy]
url = "https://rivers-sin-resistant-bigger.trycloudflare.com/app/ClientRequests"
subpath = "proxy943"
prefix = "apps"
 
 
this is my app.ClientRequests route, 
import shopify from "../shopify.server";
export async function action({requestparams}) {
const { admin } = await shopify.authenticate.public.appProxy(request);
const formData = await request.formData();
const productData = Object.fromEntries(formData);
const variantId = productData.productId;
const response = await admin.graphql(`
{
node(id"${variantId}") {
... on ProductVariant {
id
sku
title
price
product {
id
title
description
handle
featuredImage {
height
url
altText
}
}
}
}
}`);

 

const jsonResponse = await response.json();
return new Response(JSON.stringify(jsonResponse), {
status: 200,
headers: {
'Content-Type': 'application/json',
},
});
}
 
why would I get a 404 error?
CodeCodeCode
Shopify Partner
4 0 1

Shouldn't the signature be auto generated?

 

tmancode
Shopify Partner
1 0 0

Can you please share a link on how to sign a request.

iffikhan30
Shopify Partner
246 35 44

Hello Hacun3jr,

 

I figure out problem you want to show your data on publicly, but you add admin auth when you remove this line await authenticate.admin(request); code is working, same issue i stuck, I figured out this promblem hope this is helps you.

Custom theme and app [remix] expert.

Email: irfan.sarwar.khan30@gmail.com
Chat on WhatsApp
Connor_Ingold
Shopify Partner
1 0 0

I was wondering if you could expand on this a little bit more? I'm having the same issue with my code:

location.tsx:

import { json } from "@remix-run/node";
import { authenticate } from "../shopify.server";
import type { LoaderFunction } from "@remix-run/node";
import { useLoaderData } from "@remix-run/react";


export const loader: LoaderFunction = async ({ request }) => {
  const { admin } = await authenticate.public.appProxy(request);

  const response = await admin?.graphql(
    `#graphql
    query Locations {
      locations(first: 10) {
        edges {
          node {
            id
            name
            address {
              address1
              address2
              city
              country
              province
              zip
            }
          }
        }
      }
    }`
  );
  try {
    const locationData = await response?.json();
    return json({ data: locationData })
  } catch (error) {
    console.error(error); // Log the error for server-side debugging
    return json({ error: "Failed to fetch locations", err: error }, { status: 500 });
  }
}

export default function Location() {
  const response = useLoaderData<any>();


  // Handling error state
  if (response.error) {
    return <div>Error: {response.error}</div>;
  }

  const data = response.data;

  return (
    <div>
    <h1>Locations</h1>
    {data && <pre>{JSON.stringify(data, null, 2)}</pre>}
  </div>
  );
}

Thanks!
iffikhan30
Shopify Partner
246 35 44

Hello,

 

import { authenticate } from "../shopify.server";
import prisma  from '../db.server';

export async function loader({ request, params }) {
  try {
    const shopy = await authenticate.public.appProxy(request);
    const allModels = await prisma.session.findMany({
      where: {
        shop: { equals: shopy.session.shop}
      },
    });
    const setting = await prisma.[tablename].findFirst({
      where: { shopid: shopy.session.shop }
    });
    return {
      data: JSON.stringify(setting),
    };
  } catch (error) {
    console.error(error);
    return {
      status: 500,
      data: 'An error occurred while fetching data.',
    };
  } finally {
    await prisma.$disconnect();
  }
}
Custom theme and app [remix] expert.

Email: irfan.sarwar.khan30@gmail.com
Chat on WhatsApp
Charles_Roberts
Shopify Partner
47 0 12

The problem with this approach, is that you cannot expose the admin variable, and therefore cannot use methods like:

 

admin.graphql()

 

Even when I use the correct app proxy authentication:

 

const { admin } = await authenticate.public.appProxy(request);

 

Can you show us, how you resolved this?