Re: Introducing cookieless authentication beta with App Bridge

Introducing cookieless authentication beta with App Bridge

Liam
Community Manager
3108 341 878

With the strong focus on privacy, browsers have recently started phasing out support for the 3rd party cookie. This has caused issues for embedded apps which until now have required the use of 3rd party cookies.

Our new App Bridge auth beta introduces “session tokens” to empower developers to create faster, more flexible, and more compatible apps. Session token based auth does not depend on cookies and instead relies on a Shopify-generated token that your app needs to send with every request.

In order to get started with App Bridge auth, or migrate your current app from traditional, cookie-based authentication, you can follow the guide in our developer documentation.

Questions about App Bridge auth or session tokens? Post them in this board or reach out to support through your partner dashboard.

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

Replies 133 (133)
optizio
Shopify Partner
13 0 6

@HunkyBill - Yes that's right, tested extremely thoroughly and agree with your sentiment. I can replicate the issue on my own app, as well as many big production apps, when I block ALL third party cookies (either manually or by browsing in incognito mode). If they are testing in Incognito mode, I'm of the opinion that all apps that use cookies will fail review with this infinite loop issue (it happens with the default app built with the Shopify cli (node)).

optizio
Shopify Partner
13 0 6

Just to add to the topic at hand. If you are implementing cookie-less auth and use { authenticatedFetch } - make sure you use the exact version mentioned in the docs here (https://shopify.dev/tutorials/authenticate-your-app-using-session-tokens) (1.23.0) - newer versions fail when proxying graphql requests. Having already spent hours figuring out that a patch version bump was the cause of my pain, I haven't had the time to figure out exactly what's different in those two versions!

To be fair, it does state you 'NEED' that version, silly me 😉

HunkyBill
Shopify Partner
4853 60 562

This thread is supposed to be nothing but an intro to JWT being useful for Apps. We should collectively try and establish other threads for other problems. If oAuth to establish credentials is somehow borked with a Node App, it belongs in a Node oAuth thread. Otherwise we are all losing focus on the aspect of what is actually a problem, and for who.

Custom Shopify Apps built just for you! hunkybill@gmail.com http://www.resistorsoftware.com
assafl
Shopify Partner
16 0 5

Hi everyone,

This thread is great knowledge base for the session tokens subject

Thank you @KisukaKiza and @MathewsJoseph for your great contributions

 

However, I didn't get to see any response from Shopify team about official way to do this, must I remove koa packages and implement authentication logic on my own in order to use the new functionality?

Isn't there an official support planned to provide managed components integrated with it?

 

Would be great to get an official response here

 

JoshHighland
Shopify Partner
213 12 76

Can I get clarity on "dest" in the decoded JWT payload?

will "dest" ALWAYS be the *.myshopify.com account name, or can it be the TLD?

Example:

Domain = myshop.com
Shopify Account = myshop.myshopify.com

In the JWT payload will:

dest = myshop.com
or
dest = myshop.myshopify.com

SEO Manager - The all-in-One SEO solution for Shopify
A powerful suite of SEO tools that gets you found in Google results

- Install SEO Manager -
Adriano_Corte_R
Shopify Partner
6 0 9

The dest field is always `https://{SHOP}.myshopify.com`

TwoColors
Shopify Partner
78 0 23

Why can't we just simply get this cookieless authentication integrated into Shopify App CLI? That way we can just set up some test project and see how it works, this would cut off half of the questions here. I have app with NodeJS (Koa) and React generated with Shopify App CLI, I would love to simply generate new project and compare it.

Maciej Tokarczyk
Michael_Ragalie
Shopify Staff
38 2 12

Thanks for the feedback and ideas! We want to make building with session tokens a straightforward experience, so we'll take these ideas back as we consider future improvements.

To learn more visit the Shopify Help Center or the Community Blog.

assafl
Shopify Partner
16 0 5

@Michael_Ragalie thanks for the update

Can you share timeframe for the updates to be available?

assafl
Shopify Partner
16 0 5

@Michael_Ragalie Would be great to hear of any updates on this

Michael_Ragalie
Shopify Staff
38 2 12

Hi! We're actively improving the tooling around this feature. For example, we recently shipped improvements to how session tokens operate in server-side rendered Safari apps: https://github.com/Shopify/shopify_app/issues/1101

We don't give guidance on when particular features will be implemented so that we have the flexibility to adjust the roadmap as new problems and opportunities appear.

To learn more visit the Shopify Help Center or the Community Blog.

assafl
Shopify Partner
16 0 5

@Michael_Ragalie thanks for your response

My issue here is that there is a guidance which is not adjusted to this great new feature which looks pretty much baked.

Since the original guidance is well documented and officially supported I would expect this feature to be so as well

Adjusting to the new feature currently means removing important SDK packages and implementing infrastructure logic on my own. It causes me to handle a lot more than just the pure business needs of my app which is not the best way to go.. 

Do you recommend to use the solutions suggested by our great community here or should we wait for an official SDK support?

Adriano_Corte_R
Shopify Partner
6 0 9

Maybe this might help those of you who are having a hard time.

Not entirely sure if the way I'm doing it is perfectly sound or "best practices" but it works for me. If you're using the pre-built sample nodejs or ruby apps that Shopify provides then I don't know what you'll need to do exactly to make it work but for me it works the following way:

(disclaimer: my backend is in Golang, not NodeJS or RoR)

I added a middleware to my backend routes that expects to receive a JWT as a Bearer token in the headers. This middleware is responsible for decoding and verifying the JWT on each and every request to any of the "protected" routes.

My frontent loads inside Shopify unauthenticated and it initializes appbridge and grabs a token through appbridge. I then make a call to my backend to check if this particular store is in the database. This backend call includes the JWT Bearer token I mentioned earlier. If the backend properly verifies the JWT string and the store is present/located in my database, it returns a 200 status which my frontend takes as a sign that we're good to proceed and everything is OK. If the backend returns a 4xx or 5xx status code, the frontend uses appbridge to redirect the parent window/tab to the Shopify app install URL for my particular app. From there the process repeats and any calls to the backend includes the JWT Bearer token. Any calls to the backend without the token fails with a 401 status. 

If you go this route make sure to properly verify the JWT signature and validate the NBF and EXP fields in the JWT string.

HunkyBill
Shopify Partner
4853 60 562

Nice job Adriano! That reads as textbook perfecto!

Custom Shopify Apps built just for you! hunkybill@gmail.com http://www.resistorsoftware.com
ptrck_schndr
Shopify Partner
11 0 11

Hi there. The new App Bridge seems to a be a very modern way of embedding apps into the Shopify admin. Congrats for this huge improvement. I really love this!

I'm very well-known into the basic concepts of JWT and how it works to decrypt it and check if it's valid or not. No problem for me at this point.

But still I have a really hard time to even get it just simply running through the OAuth-process on the first install, although I'm doing it exactly how it is described in the manuals.

Can someone please explain what I am doing wrong here?

/auth/index.html

 

import createApp from '@shopify/app-bridge';
import { Redirect } from '@shopify/app-bridge/actions';

const shopOrigin = 'xxxxxxxxxxxx.myshopify.com';
const apiKey = 'xxxxxxxxxxxx';
const redirectUri = 'https://xxxxxxxxxxxx.ngrok.io/';
const scopes = [
    'read_products',
    'read_content'
];
const permissionUrl = `https://${shopOrigin}/admin/oauth/authorize?client_id=${apiKey}&scope=${scopes.join(',')}&redirect_uri=${redirectUri}`;

if (window.top == window.self) {
    window.location.assign(permissionUrl);
} else {
    const app = createApp({
        apiKey: apiKey,
        shopOrigin: shopOrigin,
        forceRedirect: true
    });
    Redirect.create(app).dispatch(Redirect.Action.REMOTE, permissionUrl);
}

 

 

 

 
Inside my app settings I set the App-URL to `https://xxxxxxxxxxx.ngrok.io/auth/`

The original App is located in the root-URL, described in the redirectUri.

This works at least until I accept the OAuth-Screen in the Shopify admin, but after this it leaves the Shopify admin, opens up the redirectUri (setting hmac and code in the query) and then it gets stuck and never loads inside the Shopify admin iframe again.

Did someone get this working?


ptrck_schndr
Shopify Partner
11 0 11

Okay, so after some more investigations on this...it seems, that on an initial install of an app Shopify still tries to handle cookie session authentication on the app – after the OAuth permission prompt to accept the scopes I get a redirect loop 3 times, like https://xxxxxxxxx.ngrok.io/?code=xxxxxx&hmac=xxxxxx&shop=xxxxxxx.myshopify.com&timestamp=1613242675 – after this it breaks, goes back to the app list and shows an error like "This app can’t load due to an issue with browser cookies. Try enabling cookies in your browser, switching to another browser, or contacting the developer to get support."

BUT: after this when I click on the app the app loads normal and I can get the JWT token by using getSessionToken(app).

Is there a way to omit this redirect loop? Well, I have to admit that it is a custom app – so I think I can ignore this. But maybe I am doing things wrong with the App Bridge?

jam_chan
Shopify Partner
920 23 187

If I can store the offline access token to my session & db after OAuth, why is JWT useful?

When I need the token, I can just call request.session['access_token']. After The 1st OAuth, I can use it whenever I want unless user uninstalls my app.

From the docs, it also said that: 

Session tokens aren't a replacement for implementing OAuth with Shopify

If I must use OAuth and I can store the token in my session, why JWT? I can imagine it's useful for SPA 

 

BYOB - Build Your Own Bundles, SPO - SEO App to research keywords & edit social link preview
robbwinkle
Tourist
5 0 3

The biggest issue is if you are using something like Koa.js sessions which actually store the session in a cookie.  In an embedded Admin app this will be stored as a 3rd party cookie in an iFrame. Because this is the same method used for ad tracking, there are some hoops to jump through in the Shopify App Bridge to get around the browser security.

If you are not using a session cookie then the session token JWT won't be an advantage.  If for example you were storing the session in Redis you would never hit the 3rd party cookie issue.  Or if you are not embedding your app you also would not see the issue.

There is also the issue of switching between multiple shops which I ran into with the session cookie approach.  If you switch tabs the session will contain a reference to one of the shops.  I added the session cookie on each request to my server and a Koa middleware to check against the session cookie shop. On the client side I refresh the iFrame to force the OAuth dance again. As a side effect the shop parameter needs maintained across links.  If I didn't already have an existing codebase I would have just started with the session tokens and handling the OAuth dance myself in the app instead of relying on the Shopify package.

jam_chan
Shopify Partner
920 23 187

@robbwinkle 

Thanks for your detailed explanation. My stack is Python / Django. I used to store sessions in my db. So cookie isn't a serious issue for me. 

However, merchants switching between multiple shops is always is a nightmare for me. When the merchant is using my app in different tabs for multiple shops, the session data always messes up. For a long time, I can't think of a good way to solve the problem. JWT sounds like a good solution for this scenario.

BYOB - Build Your Own Bundles, SPO - SEO App to research keywords & edit social link preview
tonypmuk
Shopify Partner
8 0 6

I was working on my first Shopify App.  When I tried to rebuild my app with the latest version of App CLI (rails), I was thrown off balance by the addition of the session token code.  This thread helped, but I could not see how I was going to extend the concept into the rails framework. The cli puts some sample code in the home controller but it I could not quite see where to go from there.  I saw the comment that suggested using turbolinks, and I found some general steps.  However all became clear when I discovered the sample app https://github.com/Shopify/turbolinks-jwt-sample-app.  Once I got that running, the mist cleared.  I know I am not the sharpest pencil in the box, but I thought it may help someone else struggling as I was.  I think I found the link to the sample app somewhere in the Shopify Docs, but hitting on the right bit of documentation (and clicking on the right link) is not always easy.

 

 

HunkyBill
Shopify Partner
4853 60 562

It is just unfortunate that Turbolinks is the example, especially in the case that:

1. Turbolinks is pretty much a dead pattern, now being actively replaced by the newer patterns from DHH and,

2. A lot of Apps are built such that they do not even need Turbolinks

So a cleaner approach would have been to demo the use of the JWT with more clarity.I am happy they continue churning through the big change! It is starting to make some sense in the Shopify App sense. But still, at some point, I see spinners and blank screens even with flagship internal Shopify Apps meaning they have not yet perfected deployment even amongst their own stable of code.

Custom Shopify Apps built just for you! hunkybill@gmail.com http://www.resistorsoftware.com
tonypmuk
Shopify Partner
8 0 6

Thank you for your comments.  I fully take your point about turbolinks.

I am working on a small app, and have dispensed with turbolinks and the extra code added to make tubolinks work.  I am doing page updates using rails templates and ajax requests. 

I have a couple of things that I would welcome some help with.

1.  keepRetrievingToken.  this was added to shopify_app.js for turbolinks, and I have added a similar function in my non-turbolinks app.  Without it I get token expired failure.  Since there is no mention of having to poll the session token for other shopify app session token examples, I figure I should be able to avoid it, but don't know how this is done.

2.  When I get an auth fail, my app redirects to the login page, but this does not get rendered because I am expecting an ajax request.  At least that is what I think is happening. 

I am starting out with React.js and like what I see.  I have built and installed the next-gen-auth-app-demo,  I cant really see how to extend the app from the basic home page to add pages to the app. Nor can I see if it would be necessary to poll the session token to keep it live in this app, and indeed if not why.

 

 

 

tonypmuk
Shopify Partner
8 0 6

OK, regarding the next-gen demo app, I see that the piece of the puzzle I was missing wat react.js/react-rails.  I have only just noticed that this was built into the demo app, and that react-ujs and react-router will be the keys to understanding how to add more resources to the app.  Which should then allow me to see how session tokens co-operate with all this.

However, I still think it would be valuable to extend the example demo app just a little more to make it more apparrent how session tokens, react, routing etc fit together for this type of app.  If I find my way through it perhaps I will be able to write a little tutorial of my own (unless I am the only one out there struggling with this stuff?). 

 

darakhsa_farhan
Shopify Partner
12 0 0

Hello Sir,

When JWT token will expire after 1 minute then what to do to handle this thing in our Apps. Can you please provide step by step details for how to integrate JWT tokens part in our APP?

HunkyBill
Shopify Partner
4853 60 562

App Bridge has a getSessionToken! Use that. You get a token, you use the token. No more worrying about expired tokens.

Custom Shopify Apps built just for you! hunkybill@gmail.com http://www.resistorsoftware.com
darakhsa_farhan
Shopify Partner
12 0 0

Hello Sir,

In articles, shopify has mentioned that token life span will be 1 minute. After 1 minute, if in some case, token becomes expired when reaches to back-end then how to manage this thing and if we force users to re-login when token is stale then it will result in not good user experience as they've to login within 1 minute of interval.

Here mentioned that, we've to verify this in 6 steps >> https://shopify.dev/tutorials/authenticate-your-app-using-session-tokens#obtain-session-details-manu...

In 6 steps, we've to verify about expiry time too.

If we only verify signature and shop domain in payload will match record in our server's database then will we consider request as valid instead of considering expiry time and other factors too? Because if user does nothing in 1 minute and token will be expired then each time we've to force them to login into system which is not good.

I am stuck in this scenario. Please guide me in right direction. Thank you in advance.


assafl
Shopify Partner
16 0 5

The auth login flow should only be a redirection you make to the /auth route of your app to get a new and valid token (in Node.js its through the callback of the createShopifyAuth method of the koa-shopify-auth package) 

From end user point of view the experience is of a few more page redirects. There is no need to perform a login to the site.

jam_chan
Shopify Partner
920 23 187

How can I construct a session and activate it after decoding the JWT token?

From the doc, it said:

Add middleware that detects requests with a session token present and builds a session based on the shop and user information included in the token.

In the previous OAuth way with Python / Django, I can do this:

session = shopify.Session(shopname, API_version, access_token)
shopify.ShopifyResource.activate_session(session)

Now, how can I handle this? What should I put in for access token?

I've created an issue on Python API too.

BYOB - Build Your Own Bundles, SPO - SEO App to research keywords & edit social link preview
Michael_Ragalie
Shopify Staff
38 2 12

When we say "session" we mean data associated with a certain shop/user. The idea is that we give you the shop/user via the session token, so you can use that to look up other data about that shop/user in your system, and build whatever session object you need.

In this case, presumably you persist the access_token somewhere after you get it. (The session token changes nothing about how you get the token originally, that's still just vanilla OAuth). After you have a token, when the session token comes in via an HTTP request, you can look up the access_token using the shop information in the session token, then run the code to build and activate the "Shopify session".

To learn more visit the Shopify Help Center or the Community Blog.

JHLEE
Tourist
6 0 1

Hi @Michael_Ragalie,

I'm trying migrate Shopify Embedded App from cookie based access token into session token.  I was able to get session token using following tutorial: https://github.com/Shopify/shopify-app-node

And now I need to get the access token in order to call REST API.   Based on the your comment below:

"you can look up the access_token using the shop information in the session token, then run the code to build and activate the "Shopify session".  

I believe there is way to get the access token from the session token.   I am wondering if you can share some sample code to accomplish the task.  I am using Node and React. 

Thanks,

Michael_Ragalie
Shopify Staff
38 2 12
Hi!

You can't get the access token from the session token, but the session
token tells you which shop is accessing your app. If you already have an
access token persisted to your database for that shop (from a prior OAuth
run), then you can look up the access token in your database using the shop
domain.

To learn more visit the Shopify Help Center or the Community Blog.

JHLEE
Tourist
6 0 1

Hi @Michael_Ragalie ,

I see.  I need to setup a database in order to store the access token for the shop.  That was the reason I couldn't find any reference to call REST API via session token.  It makes sense now.

Thanks for the reply, really appreciated.

gatanik
Visitor
2 0 0

A digital storytelling blog touching upon themes and trends in eCommerce, tech trends, retail, and CPG. Sharing my close to 15 years of experience in the technology sector

Louise_Elmose_H
Shopify Partner
78 2 21

Hi,
I am trying to figure out how to change my existing apps to use session tokens.

I think I should use getSessionToken(app) where "app" is the app bridge. 

I am able to get an instance of the app bridge, but calling functions on the app bridge never seems to terminate - what am I doing wrong?
Please note that I have checked that the "App url" of the app configuration matches the localOrigin of the app bridge, and I run the application locally using ngrok, and it is an embedded app.


The _app.js code is:

 

import App from 'next/app'
import Head from 'next/head'
import { AppProvider } from '@shopify/polaris'
import { Provider } from '@shopify/app-bridge-react'
import '@shopify/polaris/styles.css'
import translations from '@shopify/polaris/locales/da.json'

class ShopifyApp extends App {
  state = {
    //Mocking successfull OAuth
    authenticated: true,
  }

  getContent(){
    if (this.state.authenticated){
      const { Component, pageProps } = this.props
      
      //Shop hardcoded in order to simplify example
      const config = { apiKey: SHOPIFY_APP_KEY, shopOrigin: 'your-test-shop', forceRedirect: true }
      return (
        <Provider config={config}>
          <AppProvider i18n={translations}>
            <Component {...pageProps} />
          </AppProvider>
        </Provider>
      )
    }else{
      return (
        <p>Not authenticated</p>
      )
    }
  }

  render() {
    return (
      <React.Fragment>
        <Head>
          <title>Shopify App</title>
          <meta charSet="utf-8" />
        </Head>
          {this.getContent()}
      </React.Fragment>
    )
  }
}

export default ShopifyApp

 

The index.js code is:

 

import { Heading } from '@shopify/polaris'
import { useAppBridge } from '@shopify/app-bridge-react'
import { getSessionToken  } from '@shopify/app-bridge-utils'

export default function Index(props) {
  const app = useAppBridge()
  //Check that app.localOrigin matches the "App url" defined in the app configuration?
  console.log('Use app bridge app:', app)

  //Why is neither the "then" nor the "catch" clause for getState executed?
  app.getState()
    .then((state) => console.log('state: ' + state))
    .catch((err) => console.log('state error ' + err))

  //Why is neither the "then" nor the "catch" clause for getSessionToken executed?
  getSessionToken(app)
    .then((result) => console.log('token ' + result))
    .catch((err) => console.log('token err' + err))
  
  return <Heading>Hello!</Heading>
}

 

I am a frontend rookie, so my apologies in advance if I missed something basic.

Thanks,
-Louise