ozzyonfire / shopify-next-app

Shopify app template on Next.js with app directory
https://shopify-next-app-six.vercel.app
MIT License
64 stars 7 forks source link

OAuth flow is in redirect loop #7

Closed trnc-ck closed 7 months ago

trnc-ck commented 8 months ago

hey,

we tried out your boilerplate and changed the session storage to postgres, by refactoring just the loading/creating/finding sessions in the db. this seems to work, as it can write sessions and read them. problem is:

after being redirect by the shopify oauth screen to / it keeps opening new windows. here's the console log:

  1. when installing the app and it displays the shopify oauth screen:
11:49:32 │ next app │ isInstalled false
11:49:32 │ next app │ [shopify-api/INFO] Beginning OAuth | {shop: ######REDACTED######.myshopify.com, isOnline: false, callbackPath: /api/auth/callback}
11:49:32 │ next app │ [shopify-api/DEBUG] OAuth started, redirecting to https://######REDACTED######.myshopify.com/admin/oauth/authorize?client_id=b1e998f4498c4e26416aab61cd10f695&scope=write_products&redire
ct_uri=https%3A%2F%2Fdistricts-direction-ebook-sleep.trycloudflare.com%2Fapi%2Fauth%2Fcallback&state=645357476446240&grant_options%5B%5D= | {shop: ######REDACTED######.myshopify.com, isOnline: false}
  1. when clicking install, it creates 1 online and 1 offline session in the db. afterwards it trys to redirect, but keeps opening new browser tabs. log looks like this:
11:49:49 │ next app │ [shopify-api/INFO] Completing OAuth | {shop: ######REDACTED######.myshopify.com}
11:49:49 │ next app │ [shopify-api/DEBUG] OAuth request is valid, requesting access token | {shop: ######REDACTED######.myshopify.com}
11:49:49 │ next app │ [shopify-api/INFO] Creating new session | {shop: ######REDACTED######.myshopify.com, isOnline: false}
11:49:49 │ next app │ [shopify-api/INFO] Registering webhooks | {shop: ######REDACTED######.myshopify.com}
11:49:50 │ next app │ [shopify-api/DEBUG] Existing topics: [] | {shop: ######REDACTED######.myshopify.com}
11:49:50 │ next app │ [shopify-api/DEBUG] Running webhook mutation | {topic: APP_UNINSTALLED, operation: create}
11:49:53 │ next app │ isInstalled true
11:49:53 │ next app │ Handlers already added
11:49:53 │ next app │ [shopify-api/INFO] Registering webhooks | {shop: ######REDACTED######.myshopify.com}
11:49:53 │ next app │ [shopify-api/DEBUG] Existing topics: [APP_UNINSTALLED] | {shop: ######REDACTED######.myshopify.com}
11:49:53 │ next app │ Webhooks added {
11:49:53 │ next app │   CUSTOMERS_DATA_REQUEST: [],
11:49:53 │ next app │   CUSTOMERS_REDACT: [],
11:49:53 │ next app │   SHOP_REDACT: [],
11:49:53 │ next app │   APP_UNINSTALLED: []
11:49:53 │ next app │ }
11:49:55 │ next app │ isInstalled true
11:49:55 │ next app │ Handlers already added
11:49:55 │ next app │ [shopify-api/INFO] Registering webhooks | {shop: ######REDACTED######.myshopify.com}
11:49:55 │ next app │ [shopify-api/DEBUG] Existing topics: [APP_UNINSTALLED] | {shop: ######REDACTED######.myshopify.com}
11:49:55 │ next app │ Webhooks added {
11:49:55 │ next app │   CUSTOMERS_DATA_REQUEST: [],
11:49:55 │ next app │   CUSTOMERS_REDACT: [],
11:49:55 │ next app │   SHOP_REDACT: [],
11:49:55 │ next app │   APP_UNINSTALLED: []
11:49:55 │ next app │ }
11:49:57 │ next app │ [shopify-api/INFO] Beginning OAuth | {shop: ######REDACTED######.myshopify.com, isOnline: true, callbackPath: /api/auth/callback}
11:49:57 │ next app │ [shopify-api/DEBUG] OAuth started, redirecting to https://######REDACTED######.myshopify.com/admin/oauth/authorize?client_id=b1e998f4498c4e26416aab61cd10f695&scope=write_products&redire
ct_uri=https%3A%2F%2Fdistricts-direction-ebook-sleep.trycloudflare.com%2Fapi%2Fauth%2Fcallback&state=550620417132146&grant_options%5B%5D=per-user | {shop: ######REDACTED######.myshopify.com, isOnline: true}
11:49:58 │ next app │ [shopify-api/INFO] Completing OAuth | {shop: ######REDACTED######.myshopify.com}
11:49:58 │ next app │ [shopify-api/DEBUG] OAuth request is valid, requesting access token | {shop: ######REDACTED######.myshopify.com}
11:49:58 │ next app │ [shopify-api/INFO] Creating new session | {shop: ######REDACTED######.myshopify.com, isOnline: true}
11:49:58 │ next app │ [shopify-api/INFO] Registering webhooks | {shop: ######REDACTED######.myshopify.com}
11:49:58 │ next app │ [shopify-api/DEBUG] Existing topics: [APP_UNINSTALLED] | {shop: ######REDACTED######.myshopify.com}
11:49:59 │ next app │ [shopify-api/INFO] Beginning OAuth | {shop: ######REDACTED######.myshopify.com, isOnline: true, callbackPath: /api/auth/callback}
11:49:59 │ next app │ [shopify-api/DEBUG] OAuth started, redirecting to https://######REDACTED######.myshopify.com/admin/oauth/authorize?client_id=b1e998f4498c4e26416aab61cd10f695&scope=write_products&redire
ct_uri=https%3A%2F%2Fdistricts-direction-ebook-sleep.trycloudflare.com%2Fapi%2Fauth%2Fcallback&state=819385751159531&grant_options%5B%5D=per-user | {shop: ######REDACTED######.myshopify.com, isOnline: true}
11:49:59 │ next app │ [shopify-api/INFO] Completing OAuth | {shop: ######REDACTED######.myshopify.com}
11:49:59 │ next app │ [shopify-api/DEBUG] OAuth request is valid, requesting access token | {shop: ######REDACTED######.myshopify.com}
11:49:59 │ next app │ [shopify-api/INFO] Creating new session | {shop: ######REDACTED######.myshopify.com, isOnline: true}
11:49:59 │ next app │ [shopify-api/INFO] Registering webhooks | {shop: ######REDACTED######.myshopify.com}
11:50:00 │ next app │ [shopify-api/DEBUG] Existing topics: [APP_UNINSTALLED] | {shop: ######REDACTED######.myshopify.com}
11:50:01 │ next app │ isInstalled true
11:50:01 │ next app │ Handlers already added
11:50:01 │ next app │ [shopify-api/INFO] Registering webhooks | {shop: ######REDACTED######.myshopify.com}
11:50:01 │ next app │ [shopify-api/DEBUG] Existing topics: [APP_UNINSTALLED] | {shop: ######REDACTED######.myshopify.com}
11:50:01 │ next app │ Webhooks added {
11:50:01 │ next app │   CUSTOMERS_DATA_REQUEST: [],
11:50:01 │ next app │   CUSTOMERS_REDACT: [],
11:50:01 │ next app │   SHOP_REDACT: [],
11:50:01 │ next app │   APP_UNINSTALLED: []
11:50:01 │ next app │ }
11:50:02 │ next app │ isInstalled true
11:50:02 │ next app │ Handlers already added
11:50:02 │ next app │ [shopify-api/INFO] Registering webhooks | {shop: ######REDACTED######.myshopify.com}
11:50:02 │ next app │ [shopify-api/DEBUG] Existing topics: [APP_UNINSTALLED] | {shop: ######REDACTED######.myshopify.com}
11:50:02 │ next app │ Webhooks added {
11:50:02 │ next app │   CUSTOMERS_DATA_REQUEST: [],
11:50:02 │ next app │   CUSTOMERS_REDACT: [],
11:50:02 │ next app │   SHOP_REDACT: [],
11:50:02 │ next app │   APP_UNINSTALLED: []
11:50:02 │ next app │ }
11:50:04 │ next app │ isInstalled true
11:50:04 │ next app │ Handlers already added
11:50:04 │ next app │ [shopify-api/INFO] Registering webhooks | {shop: ######REDACTED######.myshopify.com}
11:50:04 │ next app │ [shopify-api/DEBUG] Existing topics: [APP_UNINSTALLED] | {shop: ######REDACTED######.myshopify.com}
11:50:04 │ next app │ Webhooks added {
11:50:04 │ next app │   CUSTOMERS_DATA_REQUEST: [],
11:50:04 │ next app │   CUSTOMERS_REDACT: [],
11:50:04 │ next app │   SHOP_REDACT: [],
11:50:04 │ next app │   APP_UNINSTALLED: []
11:50:04 │ next app │ }
11:50:04 │ next app │ isInstalled true
11:50:04 │ next app │ Handlers already added
11:50:04 │ next app │ [shopify-api/INFO] Registering webhooks | {shop: ######REDACTED######.myshopify.com}
11:50:04 │ next app │ [shopify-api/DEBUG] Existing topics: [APP_UNINSTALLED] | {shop: ######REDACTED######.myshopify.com}
11:50:04 │ next app │ Webhooks added {
11:50:04 │ next app │   CUSTOMERS_DATA_REQUEST: [],
11:50:04 │ next app │   CUSTOMERS_REDACT: [],
11:50:04 │ next app │   SHOP_REDACT: [],
11:50:04 │ next app │   APP_UNINSTALLED: []
11:50:04 │ next app │ }
11:50:07 │ next app │ [shopify-api/INFO] Beginning OAuth | {shop: ######REDACTED######.myshopify.com, isOnline: true, callbackPath: /api/auth/callback}
11:50:07 │ next app │ [shopify-api/DEBUG] OAuth started, redirecting to https://######REDACTED######.myshopify.com/admin/oauth/authorize?client_id=b1e998f4498c4e26416aab61cd10f695&scope=write_products&redire
ct_uri=https%3A%2F%2Fdistricts-direction-ebook-sleep.trycloudflare.com%2Fapi%2Fauth%2Fcallback&state=408148165774158&grant_options%5B%5D=per-user | {shop: ######REDACTED######.myshopify.com, isOnline: true}
11:50:07 │ next app │ [shopify-api/INFO] Completing OAuth | {shop: ######REDACTED######.myshopify.com}
11:50:07 │ next app │ [shopify-api/DEBUG] OAuth request is valid, requesting access token | {shop: ######REDACTED######.myshopify.com}
11:50:08 │ next app │ [shopify-api/INFO] Creating new session | {shop: ######REDACTED######.myshopify.com, isOnline: true}
11:50:08 │ next app │ [shopify-api/INFO] Registering webhooks | {shop: ######REDACTED######.myshopify.com}
11:50:08 │ next app │ [shopify-api/DEBUG] Existing topics: [APP_UNINSTALLED] | {shop: ######REDACTED######.myshopify.com}

any idea? can't believe that this occurs because of the switch to postgres.

Wkasel commented 7 months ago

+1 on this. Also using PG (via Supabase).

Getting an oAuth redir loop.

@trnc-ck any luck on your end?

ozzyonfire commented 7 months ago

Sorry, I've been stuck on another project but I will try to take a look over the next couple of days. Been meaning to add in some example code for postgres (on prisma or something). I'll check it out

trnc-ck commented 7 months ago

@ozzyonfire sure. here's the session storage. the "content" col is a json field. from the data side everything seems okay, also the logs.

import { Session } from "@shopify/shopify-api";
const DB_NAME = 'shopify-apps';
const apiKey = process.env.SHOPIFY_API_KEY || '';
import prisma from "./prisma";

export async function storeSession(session: Session) {
    try {
        await prisma.session.upsert({
            where: { id: session.id },
            update: {
                content: session,
                shop: session.shop,
            },
            create: {
                id: session.id,
                content: session,
                shop: session.shop,
            },
        });
        return true;
    } catch (err) {
        console.log(err);
        return false;
    }
}

export async function loadSession(id: string) {
    const record = await prisma.session.findUnique({ where: { id } });
    if (record) {
        return record.content;
    } else {
        return undefined;
    }
}

export async function deleteSession(id: string) {
    try {
        await prisma.session.deleteMany({ where: { id } });
        return true;
    } catch (err) {
        console.log(err);
        return false;
    }
}

export async function deleteSessions(ids: string[]) {
    try {
        await prisma.session.deleteMany({
            where: {
                id: {
                    in: ids
                }
            }
        });
        return true;
    } catch (err) {
        console.log(err);
        return false;
    }
}

// export async function cleanUpSession(shop: string, accessToken: string) {
//  try {
//      await db.collection('sessions').deleteOne({ shop, accessToken });
//      return true;
//  } catch (err) {
//      console.log(err);
//      return false;
//  }
// }

export async function findSessionsByShop(shop: string) {
    const records = await prisma.session.findMany({ where: { shop: shop } });
    let sessions = []
    records.forEach(element => {
        sessions.push(element.content)
    })
    if (sessions) {
        return sessions;
    }
    return [];
}
ozzyonfire commented 7 months ago

I just updated a bunch of stuff on the repo.

Now you will find a prisma example that uses postgres. I was able to get it running smoothly in my dev environment. Let me know if anything comes up

trnc-ck commented 7 months ago

Thx @ozzyonfire for your effort. Will check it out!