-
Notifications
You must be signed in to change notification settings - Fork 63
Embedded app cannot complete OAuth process, and custom session storage documentation #64
Comments
Hey @jt274, thanks for this. To answer your questions:
Are you doing anything differently to run into the error you mention?
|
@paulomarg Thanks - the documentation from that PR is the best so far. I guess another question I have is about the session in general. In the previous Node/React tutorial, I don't remember anything about sessions. The libraries seemed to do all of it for you. I am not familiar with Redis. In the example, using Redis, it would store the session data locally? I'm not seeing from the example how the |
In the previous iteration, we used Our package still handles all of the logic behind sessions, and Hope this helps clear things up for you and others who end up here from searches! |
@paulomarg I understand about the cookies, just not sure how the sessions all worked. Makes sense. So using the I will try to get it working. If I do I'm willing to post the code. |
@paulomarg I am slowly getting somewhere. I've stored the session data to my database of choice, and am able to load it back. But when I do I get an error in the If I do either one of these (where session is the returned session that's been loaded):
I get this error: The session is storing the id, shop, state, and isOnline parameters. |
@jt274 I think I'm at the same point as you. I've implemented my This is currently my
Maybe I'm doing it wrong after reading the following comment from @paulomarg here: I want to know if that's the right way to do it, or maybe I just misunderstood it. Also, I've been having a hard time with the
When and where should we set/update this object? I have some other questions about custom routes (i.e. navigation elements in embedded app, can't display the pages on them) and verifyRequest, but I think I should find another issue more related to that. |
I was finally able to store and load a session during the auth with some messy code in the
The
I now continue to have graphql errors, such as |
@jt274 are you using online or offline access token? I'm currently using offline tokens, should I use online tokens as well? Also, that info about the owner, did you generate it or was autogenerated? |
@ilugobayo Can't find it now, but docs somewhere mentioned using online tokens for apps in the user facing admin, and offline were for a database backend that makes requests without the user interface. When going through the Oauth, it initially creates a token in the database that only has the Now I'm figuring out why it appears I've created and loaded tokens but graphql requests no longer work. |
I also don't understand how to choose access-mode. !Edited!
|
@jt274 it's really weird, in my case, the starting session object has only |
@kato-takaomi-ams maybe that's where I'm failing? I'm only using the offline access mode, I'm not sure if I should be using online as well, I mean, I have an UI for the merchant, but most of what my app does requires offline access mode since its features involve several request to the Shopify Admin API |
Hey all, let me see if I can shed a bit of light here. The We've added support for As far as online vs offline sessions go, you can read up on how they work in our documentation. Essentially, online tokens are best suited for cases where users are directly interacting with your app, whereas offline tokens work better for background tasks, since they don't expire and are tied to the shop as a whole. Hope this helps! |
@paulomarg thanks for this comment, I just have some questions about this:
|
@ilugobayo I am not sure if this helps, but my app has the merchant interacting with it, as well as back-end things that happen with webhooks. I am using the |
@jt274 thanks, I think using I actually do the same with the By the way, do you store the |
@ilugobayo I suppose that could happen? I have it update the I am using Firestore, and store the token/app information in one collection, and sessions in another. When I store the sessions, I put in everything that is given. Since Firestore already is JSON essentially, I just write the |
@jt274 interesting, I think this is just getting clearer for me. Now I just need to figure out why even if my Also, do you perform any checks on scope changes? If so, do you do it in |
@ilugobayo Have not worked on the scope changes yet, that also seems new. Still some smaller things like that to get done. I think mine was doing something similar, but making sure the It does, however, create two sessions still. It creates one with a random id, populates all of it, then creates a second identical (minus slightly later expires timestamp) named |
Couple of comments:
|
@jt274 Ok ok, this is just getting more and more interesting. I will test all this with Thank you so much for taking time to answer my questions, I might bother you once again if I find some more issues, I hope you can help me then once again.
Thanks for making it clearer! |
@paulomarg I think this issue is mostly resolved, but one more question. Is the online/offline token you're referring to the Because before all these auth changes, I simply stored the |
@jt274 exactly my concern. That's why my first approach was to use |
@ilugobayo I am not sure. It appears the |
Think I've got my answer: https://shopify.dev/concepts/about-apis/authentication#api-access-modes |
@jt274 I was about to link you that. As you can see, the scenario where the |
@ilugobayo I think offline is the way to go. I've attempted to switch to offline and have new issues. :) During auth, a session named I have set |
@jt274 using My problem is what I mentioned above, that my Did you notice that the session By the way, I forgot to ask before, are you persisting the |
@paulomarg does this mean it is possible to use both modes? If so, can you provide a brief example on how to implement it? |
I am able to use graphql from my storefront without the |
@nandezer the app will work fine for a while, but if the session is invalid, it won't load nor properly perform requests to the server; though the customer could easily hit one of the other pages that are not "/", and it would automatically go to "/auth", since everything else requires a session, but that's completely awful UX. |
To be honest, I mainly need the offline tokens (for now). But I see how that can be a problem when I have to make it more interactive, thanks!. |
Hey @ilugobayo with the initialisations to get both the online & offline tokens, have you come accross any problems with webhook triggers? I had understood that the point of registering those webhooks with offline tokens would avoid that problem (I initially had it after 24h, as my online token session expired). Here is how my code looks like:
I'm not sure what is wrong, as the webhooks are created with an offline token, meaning they should be able to be called at any given time right? PS: As I said on my previous comment, I need to be able to do graphql mutations to allow for my app to be deactivated, hence I need to have both online and offline tokens. |
The code for finding sessionId tells us that it looks at the When loading say the So does anyone know who is responsible for setting the session cookie on your app's domain? Why is this so hard and why aren't the examples working? Am I way off the beaten path? I just want the simplest way to get an app working that can make front-end Graphql calls. |
@nolandg I'm in the same place. I posted about that exact issue here: Shopify/shopify-api-js#162 I am able to actually load the session token on the front end using I removed the Would @paulomarg have any input on this? |
@nandezer well, I'm not really sure about the GraphQL stuff since I don't use that myself, but here's how I have my webhooks registrations and their handlers, first the registrations inside the
And the handlers, for which I'm using an endpoint for each one of them:
I honestly didn't want to handle everything in a single endpoint because it would be a mess to validate which webhook was triggered and what actions should be performed. The only case in which I use Hope this helps you, let me know if you have more questions. |
I think I found a workaround for the issue when Since I'm using REST endpoints for all my requests to my app/server to request data and perform actions, I implemented At first I was testing only with online access sessions, and whenever the session was invalid for whatever reason, this can be that it was already expired, the scopes changed or the bug I discovered, my requests wouldn't work. In the first two cases, it's pretty obvious why the session was invalid, and in theory, I needed to check/validate that in After implementing both access modes simultaneously, online & offline, the third case "wasn't an issue anymore", because now my requests to the Shopify API would use the offline access token, which never changes; but the first two cases persisted, this time my app would try to retrieve the data from the server and since the session token is invalid, the endpoints would return a This is when I came up with this workaround since I had no options left, this is my code in the frontend for when I perform a request to the server:
The line As you can see, there's the Finally, as you can see in the This pretty much simulates the validation in the server, at least in my case, since I perform these request before displaying any data on my pages, so the redirection will happen when the merchant opens the app and the skeleton page is being displayed. I know it's not the optimal solution, but it was the only way I found to finally complete the whole JWT authentication change in my app after being stuck with it for more than a month. I've been testing for both cases, when the expiration date is in the past and when the scopes are different, and in both of them the app redirects to I hope this can help someone or maybe guide them to find a solution. |
How come the only place you use |
@nandezer sorry for the late reply. For me it works fine with no issues, my webhooks trigger and execute everything as expected. I saw in your previous post when you showed your code that you had this line |
It was giving me problems when I had it actually. I think it on the frontend while doing the graphql query (I have done so many changes since then that I can rememeber at this point). |
@ilugobayo @jt274 thanks for sharing your process in this thread. It really helped me make progress 🙏 I decided to implement both an online and offline tokens following your blueprint. I'm trying to wrap my head around why I'm stuck at the first auth step because of an error. When trying to create an offline token I'm getting a 'InternalServerError: Mismatched data types provided: string and undefined' that originates from the load session callback. I noticed you were able to overcome it, can you please share your insights? Thx! |
A small comment for anyone else having trouble surrounding the session retrieval with, When you're first going through OAuth and you're redirected outside of the admin area there are session cookies that are checked instead of the router.get("/", async (ctx) => {
const shop = ctx.query.shop;
if (ACTIVE_SHOPIFY_SHOPS[shop] === undefined) {
ctx.redirect(`/auth?shop=${shop}`);
} else {
const session = await Shopify.Utils.loadCurrentSession(req, res);
console.log(session); // undefined most of the time
await handleRequest(ctx);
}
}); The token is not set automatically though, which is why the I don't believe it's expected that you would have access to the session in the first unauthenticated |
Has anyone figured out how to handle the expiration of the online access token while a user is interacting with the app? Should I just redirect the user to OAuth flow to get a new online access token whenever a request to the Shopify server fails? |
Can someone explain how to do this? |
Can anyone help me in getting the permanent access token (access_token as per docs). Where and how in server.js, I have to make a post request to get the permanent access token. |
Can anyone please help me with this I am new to Shopify app development? db.js file =>>>>>>> import { Session } from "@shopify/shopify-api/dist/auth/session/session.js"; var connection = mysql.createConnection({ connection.connect(); let domain_id = ''; const payload = {...session}
return true;
} // not used yet
}
} Index file =>>>>>>>>>>>> // @ts-check import applyAuthMiddleware from "./middleware/auth.js"; const PORT = parseInt(process.env.BACKEND_PORT || process.env.PORT, 10); // TODO: There should be provided by env vars const DB_PATH = Shopify.Context.initialize({ ) }); Shopify.Webhooks.Registry.addHandler("APP_UNINSTALLED", { // The transactions with Shopify will always be marked as test transactions, unless NODE_ENV is production. // This sets up the mandatory GDPR webhooks. You’ll need to fill in the endpoint // export for test use only app.use(cookieParser(Shopify.Context.API_SECRET_KEY)); applyAuthMiddleware(app, { // Do not call app.use(express.json()) before processing webhooks with // All endpoints after this point will require an active session app.get("/api/products/count", async (req, res) => {
}); app.get("/api/products/create", async (req, res) => {
}); // All endpoints after this point will have access to a request.body app.use((req, res, next) => { if (isProd) { app.use("/*", async (req, res, next) => {
}); return { app }; createServer().then(({ app }) => app.listen(PORT)); |
Note that this repo is no longer maintained and this issue will not be reviewed. Prefer the official JavaScript API library. If you still want to use Koa, see simple-koa-shopify-auth for a potential community solution. |
Issue summary
App authentication broken after updating to the "new" way of authenticating embedded apps, according to the Shopify tutorial here: https://shopify.dev/tutorials/build-a-shopify-app-with-node-and-react
The previous tutorial produced a working app.
Error: Cannot complete OAuth process. No session found for the specified shop url:
Additionally, the tutorial utilizes MemorySessionStorage, and tells you not to use it. The following page provides a vague explanation of CustomSessionStorage, but does not give enough detail for a working example: https://github.com/Shopify/shopify-node-api/blob/main/docs/issues.md#notes-on-session-handling
The app in question produces the error with MemorySessionStorage.
Expected behavior
App should authenticate once, and store the session so no further authentication is required.
Tutorials should document a fully working CustomSessionStorage example, and explain how to properly access the shopOrigin parameter throughout the React app with cookies no longer active.
Actual behavior
App re-authenticates on almost every page refresh, or displays an error: Cannot complete OAuth process. No session found for the specified shop url:. This also may produce console errors for Graphql requests such as "invalid token < in JSON"
server.js file below:
_app.js file below:
The text was updated successfully, but these errors were encountered: