[{"data":1,"prerenderedAt":486},["ShallowReactive",2],{"bootstrap":3,"blog-commerce-layer-authentication-best-practices":277},{"navigation":4,"globalConfig":196,"forms":218},{"headerSections":5,"headerFooterLinks":67,"footer":76,"legalLinks":153,"socialLinks":176},[6,39,44,50,57,62],{"hasSubMenu":7,"title":8,"links":9,"columns":38},true,"Product",[10,20,26,32],{"showTag":11,"_modelApiKey":12,"text":13,"subtitle":14,"icon":15,"isExternal":11,"link":16,"openForm":11},false,"navigation_link","Universal checkout","Sell anywhere","globe-simple",{"_modelApiKey":17,"slug":18,"title":19},"page","universal-checkout","Universal Checkout",{"showTag":11,"_modelApiKey":12,"text":21,"subtitle":22,"icon":23,"isExternal":11,"link":24,"openForm":11},"Distributed OMS","Manage orders","package",{"_modelApiKey":17,"slug":25,"title":21},"distributed-oms",{"showTag":11,"_modelApiKey":12,"text":27,"subtitle":28,"icon":29,"isExternal":11,"link":30,"openForm":11},"Promotion engine","Automated discounts","seal-percent",{"_modelApiKey":17,"slug":31,"title":27},"promotion-engine",{"showTag":11,"_modelApiKey":12,"text":33,"subtitle":34,"icon":35,"isExternal":11,"link":36,"openForm":11},"POS system","Operate stores","devices",{"_modelApiKey":17,"slug":37,"title":33},"pos-system",2,{"hasSubMenu":11,"showTag":11,"_modelApiKey":12,"text":40,"isExternal":11,"link":41,"openForm":11,"title":40},"Pricing",{"_modelApiKey":42,"slug":43},"pricing_page","pricing",{"hasSubMenu":11,"showTag":11,"_modelApiKey":12,"text":45,"isExternal":11,"link":46,"openForm":11,"title":45},"Customers",{"_modelApiKey":47,"slug":48,"title":49},"customer_landing_page","customers","Customers page",{"hasSubMenu":11,"showTag":11,"_modelApiKey":12,"text":51,"isExternal":11,"link":52,"openForm":11,"form":54,"title":51},"Partners",{"_modelApiKey":17,"slug":53,"title":51},"partners",{"_modelApiKey":55,"slug":53,"name":56},"form","PartnersForm",{"hasSubMenu":11,"showTag":11,"_modelApiKey":12,"text":58,"label":59,"isExternal":7,"url":60,"openForm":11,"title":61},"Docs Hub","Learn more","https:\u002F\u002Fdocs.commercelayer.io\u002F","Docs",{"hasSubMenu":11,"showTag":11,"_modelApiKey":12,"text":63,"isExternal":11,"link":64,"openForm":11,"title":63},"Blog",{"_modelApiKey":65,"slug":66},"blog_landing_page","blog",[68,72],{"text":69,"link":70},"Sign in",{"_modelApiKey":12,"text":69,"isExternal":7,"url":71,"openForm":11},"https:\u002F\u002Fdashboard.commercelayer.io\u002Fsign_in",{"text":73,"link":74},"Sign up for free",{"_modelApiKey":12,"text":73,"isExternal":7,"url":75,"openForm":11},"https:\u002F\u002Fdashboard.commercelayer.io\u002Fsign_up",[77,89,109,132],{"hasSubMenu":7,"title":8,"links":78},[79,81,83,85,87],{"showTag":11,"_modelApiKey":12,"text":13,"subtitle":14,"icon":15,"isExternal":11,"link":80,"openForm":11},{"_modelApiKey":17,"slug":18,"title":19},{"showTag":11,"_modelApiKey":12,"text":21,"subtitle":22,"icon":23,"isExternal":11,"link":82,"openForm":11},{"_modelApiKey":17,"slug":25,"title":21},{"showTag":11,"_modelApiKey":12,"text":27,"subtitle":28,"icon":29,"isExternal":11,"link":84,"openForm":11},{"_modelApiKey":17,"slug":31,"title":27},{"showTag":11,"_modelApiKey":12,"text":33,"subtitle":34,"icon":35,"isExternal":11,"link":86,"openForm":11},{"_modelApiKey":17,"slug":37,"title":33},{"showTag":11,"_modelApiKey":12,"text":40,"isExternal":11,"link":88,"openForm":11},{"_modelApiKey":42,"slug":43},{"hasSubMenu":7,"title":90,"links":91},"Resources",[92,94,99,104,107],{"showTag":11,"_modelApiKey":12,"text":93,"isExternal":7,"url":60,"openForm":11},"Documentation",{"showTag":11,"_modelApiKey":12,"text":95,"label":95,"isExternal":11,"link":96,"openForm":11},"Agentic Commerce",{"_modelApiKey":17,"slug":97,"title":98},"agentic-commerce-whitepaper","Agentic Commerce Whitepaper",{"showTag":11,"_modelApiKey":12,"text":100,"isExternal":11,"link":101,"openForm":11},"Core concepts",{"_modelApiKey":17,"slug":102,"title":103},"headless-commerce","Headless commerce",{"showTag":11,"_modelApiKey":12,"text":105,"isExternal":7,"url":106,"openForm":11},"Changelog","https:\u002F\u002Fdocs.commercelayer.io\u002Fchangelog\u002F",{"showTag":11,"_modelApiKey":12,"text":63,"isExternal":11,"link":108,"openForm":11},{"_modelApiKey":65,"slug":66},{"hasSubMenu":7,"title":110,"links":111},"Company",[112,116,118,121,126],{"showTag":11,"_modelApiKey":12,"text":113,"isExternal":11,"link":114,"openForm":11},"Vision",{"_modelApiKey":17,"slug":115,"title":113},"vision",{"showTag":11,"_modelApiKey":12,"text":45,"isExternal":11,"link":117,"openForm":11},{"_modelApiKey":47,"slug":48,"title":49},{"showTag":11,"_modelApiKey":12,"text":51,"isExternal":11,"link":119,"openForm":11,"form":120},{"_modelApiKey":17,"slug":53,"title":51},{"_modelApiKey":55,"slug":53,"name":56},{"showTag":11,"_modelApiKey":12,"text":122,"isExternal":11,"link":123,"openForm":11},"Security",{"_modelApiKey":17,"slug":124,"title":125},"security","Security at Commerce Layer",{"showTag":11,"_modelApiKey":12,"text":127,"label":128,"isExternal":11,"openForm":7,"form":129},"Giveback","Giveback program",{"_modelApiKey":55,"slug":130,"name":131},"giveback","GivebackForm",{"hasSubMenu":7,"title":133,"links":134},"Get in touch",[135,140,145,149],{"showTag":11,"_modelApiKey":12,"text":136,"isExternal":11,"openForm":7,"form":137},"Contact",{"_modelApiKey":55,"slug":138,"name":139},"contact","ContactUsForm",{"showTag":11,"_modelApiKey":12,"text":141,"isExternal":11,"openForm":7,"form":142},"Book a demo",{"_modelApiKey":55,"slug":143,"name":144},"demo","RequestDemoForm",{"showTag":11,"_modelApiKey":12,"text":146,"label":147,"isExternal":7,"url":148,"openForm":11},"Support","Email support","mailto:support@commercelayer.io",{"showTag":11,"_modelApiKey":12,"text":150,"label":151,"isExternal":7,"url":152,"openForm":11},"Community","Discord community","https:\u002F\u002Fdiscord.gg\u002Fcommercelayer",{"hasSubMenu":7,"title":154,"links":155},"Legal",[156,161,165,169,173],{"showTag":11,"_modelApiKey":12,"text":157,"label":158,"isExternal":7,"url":159,"openForm":11,"htmlClassNames":160},"Terms","Terms and conditions","\u002Flegal-embed\u002Fterms-of-service","iubenda-nostyle no-brand iubenda-noiframe iubenda-embed",{"showTag":11,"_modelApiKey":12,"text":162,"label":163,"isExternal":7,"url":164,"openForm":11,"htmlClassNames":160},"Privacy","Privacy policy","\u002Flegal-embed\u002Fprivacy-policy",{"showTag":11,"_modelApiKey":12,"text":166,"label":167,"isExternal":7,"url":168,"openForm":11,"htmlClassNames":160},"Cookies","Cookie policy","\u002Flegal-embed\u002Fcookie-policy",{"showTag":11,"_modelApiKey":12,"text":170,"isExternal":7,"url":171,"openForm":11,"htmlClassNames":172},"Notice at collection","#","iubenda-cs-uspr-link",{"showTag":11,"_modelApiKey":12,"text":174,"isExternal":7,"url":171,"openForm":11,"htmlClassNames":175},"Privacy preferences","iubenda-cs-preferences-link",[177,180,184,188,192],{"title":178,"type":179,"url":152,"isExternal":7},"Discord","discord-logo",{"title":181,"type":182,"url":183,"isExternal":7},"Github","github","https:\u002F\u002Fgithub.com\u002Fcommercelayer",{"title":185,"type":186,"url":187,"isExternal":7},"Bluesky","bluesky-logo","https:\u002F\u002Fbsky.app\u002Fprofile\u002Fcommercelayer.io",{"title":189,"type":190,"url":191,"isExternal":7},"X","x-logo","https:\u002F\u002Fx.com\u002Fcommercelayer",{"title":193,"type":194,"url":195,"isExternal":7},"LinkedIn","linkedin","https:\u002F\u002Fwww.linkedin.com\u002Fcompany\u002Fcommerce-layer",{"pagesWithoutCtaPanel":197,"ctaPanel":198,"notification":208,"showApiResponseTime":11,"newsletterSignup":216},[],{"title":199,"subtitle":200,"ctas":201},"Ready to get started?","Discover how we can help your business.",[202,205],{"_modelApiKey":203,"text":204,"isExternal":7,"url":75,"openForm":11},"link","Get started for free",{"_modelApiKey":203,"text":206,"isExternal":11,"openForm":7,"form":207},"Contact us",{"_modelApiKey":55,"slug":138,"name":139},{"showNotification":7,"link":209,"linkText":210,"text":215},{"_modelApiKey":203,"text":210,"isExternal":11,"link":211,"openForm":11},"Read article",{"_modelApiKey":212,"slug":213,"title":214},"blog_post","the-new-payments-api-built-for-how-people-pay-now","The new Payments API. Built for how people pay now.","\u003Cp>The new Payments API. Built for how people pay now.\u003C\u002Fp>\n",{"ctaText":217},"Subscribe",[219,225,229,236,240,246,249,253,261,262,267,272,274],{"_modelApiKey":55,"slug":220,"pardotFormEmbedCode":221,"formEmbedMinHeight":222,"successTitle":223,"successCopy":224},"agentic-commerce","https:\u002F\u002Fcommercelayer.fillout.com\u002Ft\u002F5w4Khwgxr6us?whitepaper=agentic",520,"Thank you for your request!","We’ll be in touch soon to arrange a date and time for your personalized demo.",{"_modelApiKey":55,"slug":226,"pardotFormEmbedCode":227,"formEmbedMinHeight":228,"successTitle":223,"successCopy":224},"shopify","https:\u002F\u002Fform.fillout.com\u002Ft\u002FgVnLSmKZwRus",850,{"_modelApiKey":55,"slug":130,"pardotFormEmbedCode":230,"formEmbedMinHeight":231,"displayTitle":232,"copy":233,"successTitle":234,"successCopy":235},"https:\u002F\u002Fform.fillout.com\u002Ft\u002FmVDF8aAiofus",500,"We give back.","\u003Cp>Part of Commerce Layer&#39;s company ethos is to empathize and support one another: co-workers, customers, and community. We want to do our part to help nonprofit organizations and small businesses who may feel adversely affected by the current global economic climate, and as a result, need in-kind support to reach their customers.\u003C\u002Fp>\n\n\u003Cp>If this general description matches your organization’s needs, please tell us your story by completing the following form so we can consider helping your cause.\u003C\u002Fp>\n","Thank you!","We will contact you soon to learn more about your story.",{"_modelApiKey":55,"slug":237,"pardotFormEmbedCode":227,"formEmbedMinHeight":228,"displayTitle":238,"copy":239},"book-an-onboarding-session","Book an onboarding session","\u003Cp>Schedule some time and our devs will help you set up a Commerce Layer + Sanity store.\u003C\u002Fp>\n",{"_modelApiKey":55,"slug":241,"pardotFormEmbedCode":242,"formEmbedMinHeight":243,"displayTitle":244,"successTitle":234,"successCopy":245},"download-our-whitepaper","https:\u002F\u002Fform.fillout.com\u002Ft\u002F5YPWmy8oT7us?whitepaper=ComposableCommerce",450,"Download our whitepaper.","Check your inbox. You should receive a download link soon.",{"_modelApiKey":55,"slug":247,"pardotFormEmbedCode":248,"formEmbedMinHeight":243,"displayTitle":244,"successTitle":234,"successCopy":245},"download-the-content-and-commerce-whitepaper","https:\u002F\u002Fform.fillout.com\u002Ft\u002F5YPWmy8oT7us?whitepaper=ContentAndCommerce",{"_modelApiKey":55,"slug":250,"pardotFormEmbedCode":251,"formEmbedMinHeight":243,"displayTitle":244,"copy":252,"successTitle":234,"successCopy":245},"whitepaper","https:\u002F\u002Fform.fillout.com\u002Ft\u002F5YPWmy8oT7us?whitepaper=Jamstack","\u003Cp>Commerce Layer is the perfect platform for building commerce on the Jamstack. Convert any design into pixel perfect HTML pages. Connect a best-of-breed headless CMS. Go serverless and forget the hassle of managing complex infrastructures.\u003C\u002Fp>\n",{"_modelApiKey":55,"slug":254,"pardotFormEmbedCode":255,"formEmbedMinHeight":256,"displayTitle":257,"copy":258,"successTitle":259,"successCopy":260},"contact-links","https:\u002F\u002Fform.fillout.com\u002Ft\u002FeWPyhHGHT7us",750,"Contact us.","\u003Cp>Tell us about your project. Our team will reach out to you for a personalized offer.\u003C\u002Fp>\n","Thanks for your message!","We’ll be in touch soon to discuss your project details.",{"_modelApiKey":55,"slug":138,"pardotFormEmbedCode":255,"formEmbedMinHeight":256,"displayTitle":257,"copy":258,"successTitle":259,"successCopy":260},{"_modelApiKey":55,"slug":263,"pardotFormEmbedCode":227,"formEmbedMinHeight":228,"displayTitle":264,"successTitle":265,"successCopy":266},"demo-embed","Want to see it in action? Request a demo.","Thanks for your request!","We’ll be in touch soon to arrange a date and time for your free live demo.",{"_modelApiKey":55,"slug":53,"pardotFormEmbedCode":268,"formEmbedMinHeight":228,"displayTitle":269,"copy":270,"successTitle":234,"successCopy":271},"https:\u002F\u002Fform.fillout.com\u002Ft\u002F9MTkDWMUSqus","Become our partner.","\u003Cp>Join us and get our guidance in helping your clients succeed. Our partners are our ambassadors. We are committed to your success as much as you are.\u003C\u002Fp>\n","We will contact you soon to discuss the details of our partnership.",{"_modelApiKey":55,"slug":273,"pardotFormEmbedCode":268,"formEmbedMinHeight":228,"displayTitle":269,"copy":270,"successTitle":234,"successCopy":271},"partners-embed",{"_modelApiKey":55,"slug":143,"pardotFormEmbedCode":227,"formEmbedMinHeight":228,"displayTitle":275,"copy":276,"successTitle":265,"successCopy":266},"Get a free live demo.","\u003Cp>Get a personalized demo and learn more about what Commerce Layer can do for your company.\u003C\u002Fp>\n",{"_modelApiKey":212,"link":278,"subtitle":283,"date":283,"author":284,"additionalAuthors":294,"icon":295,"abstract":296,"tag":297,"displayTitle":279,"cardRatio":299,"featured":11,"seoMetaTags":300,"layout":364,"blogPostCarousel":302,"_seoMetaTags":447,"authors":481},{"text":279,"isExternal":11,"url":280,"link":281},"Commerce Layer authentication: what you must know.","",{"_modelApiKey":212,"slug":282},"commerce-layer-authentication-best-practices","November 19, 2025",{"name":285,"picture":286},"Marco Montalbano",{"url":287,"alt":288,"title":288,"width":289,"height":289,"format":290,"focalPoint":291,"customData":293},"https:\u002F\u002Fwww.datocms-assets.com\u002F35053\u002F1763396353-marco-m.jpg","Marco Montalbano avatar",1280,"jpg",{"x":292,"y":292},0.5,{},[],"key","Understand how Commerce Layer authentication works and how to manage guest, customer, and integration tokens with proper caching, security, and real-world development patterns.",{"color":298,"name":100},"gray","portrait",[301,305,309,312,316,319,322,326,330,334,337,341,345,349,353,356,360],{"attributes":302,"tag":303,"content":304},null,"title","Commerce Layer authentication: what you must know",{"attributes":306,"tag":308,"content":302},{"property":307,"content":304},"og:title","meta",{"attributes":310,"tag":308,"content":302},{"name":311,"content":304},"twitter:title",{"attributes":313,"tag":308,"content":302},{"name":314,"content":315},"description","A simple guide to Commerce Layer authentication: how tokens work, how to pair credentials with grants, and how to keep your apps secure and efficient.",{"attributes":317,"tag":308,"content":302},{"property":318,"content":315},"og:description",{"attributes":320,"tag":308,"content":302},{"name":321,"content":315},"twitter:description",{"attributes":323,"tag":308,"content":302},{"property":324,"content":325},"og:image","https:\u002F\u002Fwww.datocms-assets.com\u002F35053\u002F1763398163-js-auth-thumb.jpg?auto=format&fit=max&w=1200",{"attributes":327,"tag":308,"content":302},{"property":328,"content":329},"og:image:width","1200",{"attributes":331,"tag":308,"content":302},{"property":332,"content":333},"og:image:height","630",{"attributes":335,"tag":308,"content":302},{"name":336,"content":325},"twitter:image",{"attributes":338,"tag":308,"content":302},{"property":339,"content":340},"og:locale","en",{"attributes":342,"tag":308,"content":302},{"property":343,"content":344},"og:type","article",{"attributes":346,"tag":308,"content":302},{"property":347,"content":348},"og:site_name","Commerce Layer",{"attributes":350,"tag":308,"content":302},{"property":351,"content":352},"article:modified_time","2025-11-25T14:20:54Z",{"attributes":354,"tag":308,"content":302},{"property":355,"content":280},"article:publisher",{"attributes":357,"tag":308,"content":302},{"name":358,"content":359},"twitter:card","summary_large_image",{"attributes":361,"tag":308,"content":302},{"name":362,"content":363},"twitter:site","@commercelayer",[365,371,382,386,390,393,396,399,407,410,415,418,421,423,426],{"_modelApiKey":366,"copy":367,"listStyle":368,"darkTheme":11,"buttons":369,"color":370,"indent":7},"wysiwyg","\u003Cp>When someone new joins Commerce Layer, our very first chat is almost always about getting to know each other, in real life \u003Cem>and\u003C\u002Fem> via API. So, whether you&#39;re just getting started or need a refresher, here&#39;s everything you need to know about authentication, tokens, and how to manage them effectively.\u003C\u002Fp>\n\n\u003Cp>Authentication is how applications prove their identity (and who they&#39;re acting on behalf of) when calling Commerce Layer APIs. Whether you&#39;re building a storefront, an integration, or an operational tool, the flow is the same: request an access token, attach it to your API calls, and refresh or revoke it as needed.\u003C\u002Fp>\n\n\u003Cp>Commerce Layer provides APIs (\u003Ca href=\"https:\u002F\u002Fdocs.commercelayer.io\u002Fcore\u002F\">Core\u003C\u002Fa>, \u003Ca href=\"https:\u002F\u002Fdocs.commercelayer.io\u002Fprovisioning\u002F\">Provisioning\u003C\u002Fa>, \u003Ca href=\"https:\u002F\u002Fdocs.commercelayer.io\u002Fmetrics\">Metrics\u003C\u002Fa>) with different access patterns. Tokens make that access explicit and auditable. The token you obtain encodes scope and ownership (guest, customer, or app), which determines exactly what the caller can do.\u003C\u002Fp>\n\n\u003Cp>If you&#39;re familiar with \u003Ca href=\"https:\u002F\u002Foauth.net\u002F2\u002F\">OAuth 2.0\u003C\u002Fa>, the concepts will feel natural — clients, secrets, grant types, access tokens, and sometimes refresh tokens:\u003C\u002Fp>\n\n\u003Cul>\n\u003Cli>\u003Cstrong>\u003Cem>API credentials define the actor\u003C\u002Fem>\u003C\u002Fstrong>---Sales channel (for customer‑facing apps) or integration (for backend services).\u003C\u002Fli>\n\u003Cli>\u003Cstrong>\u003Cem>Grant types define how you obtain the token\u003C\u002Fem>\u003C\u002Fstrong>---Client credentials, password, refresh token, JWT bearer, or authorization code.\u003C\u002Fli>\n\u003C\u002Ful>\n\n\u003Cp>In practice, you pair the right credentials with the right grant:\u003C\u002Fp>\n\n\u003Cul>\n\u003Cli>\u003Cstrong>\u003Cem>Sales channel + client credentials\u003C\u002Fem>\u003C\u002Fstrong>---Get a guest token for browsing a storefront.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>\u003Cem>Sales channel + password \u002F JWT bearer\u003C\u002Fem>\u003C\u002Fstrong>---Authenticate a known customer; optionally receive a refresh token for &quot;remember me&quot; functionality.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>\u003Cem>Integration + client credentials\u003C\u002Fem>\u003C\u002Fstrong>---Obtain a server-to-server token for background jobs, webhooks, or back-office operations.\u003C\u002Fli>\n\u003C\u002Ful>\n\n\u003Cp>We won’t go deeper here, our documentation already covers the details about \u003Ca href=\"https:\u002F\u002Fdocs.commercelayer.io\u002Fcore\u002Fapi-credentials\">API credentials\u003C\u002Fa> and \u003Ca href=\"https:\u002F\u002Fdocs.commercelayer.io\u002Fcore\u002Fauthentication\">grant types\u003C\u002Fa>.\u003C\u002Fp>\n","checkbox",[],"orange",{"_modelApiKey":372,"border":11,"caption":280,"image":373,"size":381,"darkTheme":11,"rounded":11,"color":370},"image_block",{"url":374,"alt":375,"title":375,"width":376,"height":377,"format":378,"focalPoint":379,"customData":380},"https:\u002F\u002Fwww.datocms-assets.com\u002F35053\u002F1763572558-auth-flow-diagram_padding-50.png","Auth flows diagram",1450,1712,"png",{"x":292,"y":292},{},"standard",{"_modelApiKey":366,"copy":383,"listStyle":384,"darkTheme":11,"buttons":385,"color":370,"indent":11},"\u003Ch3>Tokens don’t last forever\u003C\u002Fh3>\n\n\u003Cp>By default, tokens expire after \u003Cstrong>2 hours\u003C\u002Fstrong> for integrations or \u003Cstrong>4 hours\u003C\u002Fstrong> for sales channels. Once expired, you need to request a new one.\u003C\u002Fp>\n\n\u003Cp>However, requesting a fresh token on every API call isn&#39;t feasible. Authentication endpoint requests are not cached by Commerce Layer and are subject to \u003Ca href=\"https:\u002F\u002Fdocs.commercelayer.io\u002Fcore\u002Frate-limits\">rate limits\u003C\u002Fa>. Without proper token caching in your application, you&#39;ll quickly hit \u003Ccode>429 Too Many Requests\u003C\u002Fcode> errors.\u003C\u002Fp>\n","directional",[],{"_modelApiKey":387,"icon":388,"copy":389,"color":370},"banner","warning","\u003Cp>We strongly recommend caching the auth token so you don’t have to request a new token on every API call.\u003C\u002Fp>\n",{"_modelApiKey":366,"copy":391,"listStyle":368,"darkTheme":11,"buttons":392,"color":370,"indent":11},"\u003Cp>Depending on where your application runs, choose a storage strategy like:\u003C\u002Fp>\n\n\u003Cul>\n\u003Cli>\u003Cstrong>\u003Cem>Browsers\u003C\u002Fem>\u003C\u002Fstrong>---Prefer cookies or local storage. Consider that a cookie can also be shared with your backend so both layers use the same token.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>\u003Cem>Edge \u002F server\u003C\u002Fem>\u003C\u002Fstrong>---Use a fast store (e.g., \u003Ca href=\"https:\u002F\u002Fredis.io\u002F\">Redis\u003C\u002Fa>, \u003Ca href=\"https:\u002F\u002Fdevelopers.cloudflare.com\u002Fkv\u002F\">KV\u003C\u002Fa>). Keep separate storage for guest and customer tokens to avoid leaking a customer token to all users.\u003C\u002Fli>\n\u003C\u002Ful>\n",[],{"_modelApiKey":387,"icon":394,"copy":395,"color":370},"info","\u003Cp>Tokens can be revoked before they expire (e.g. to roll back a mistaken configuration change). If you don’t account for this, you may end up holding a non-expired token that is no longer valid.\u003C\u002Fp>\n",{"_modelApiKey":366,"copy":397,"listStyle":384,"darkTheme":11,"buttons":398,"color":370,"indent":11},"\u003Ch3>Auth library to the rescue\u003C\u002Fh3>\n\n\u003Cp>Commerce Layer \u003Ca href=\"https:\u002F\u002Fgithub.com\u002Fcommercelayer\u002Fcommercelayer-js-auth\">JS Auth\u003C\u002Fa> is a lightweight JavaScript library that simplifies authentication with Commerce Layer APIs. It works in the browser, on servers, and at the edge, so you can use it everywhere.\u003C\u002Fp>\n\n\u003Cp>Historically, you’d call the \u003Ccode>authenticate\u003C\u002Fcode> method with a grant type and a few other options to obtain an access token, then you had to manage the token cache on your own. With \u003Cstrong>v7\u003C\u002Fstrong>, we introduced a new, higher-level approach based on API credentials.\u003C\u002Fp>\n\n\u003Cp>It also includes a storage abstraction and helpers so you can cache and retrieve tokens without writing plumbing code.\u003C\u002Fp>\n\n\u003Cp>This new approach maps directly to how you build your app:\u003C\u002Fp>\n\n\u003Cul>\n\u003Cli>For storefronts, use the sales channel with \u003Ccode>makeSalesChannel()\u003C\u002Fcode>.\u003C\u002Fli>\n\u003Cli>For servers, jobs, and webhooks, use the integration with \u003Ccode>makeIntegration()\u003C\u002Fcode>.\u003C\u002Fli>\n\u003C\u002Ful>\n",[],{"_modelApiKey":400,"title":401,"preTitle":402,"linkText":403,"darkTheme":11,"link":404},"link_block","JS Auth library","Open-source","View it on GitHub",{"_modelApiKey":203,"text":405,"label":280,"subtitle":280,"icon":280,"isExternal":7,"url":406,"link":302,"anchor":280,"openForm":11,"form":302,"htmlClassNames":280},"View on GitHub","https:\u002F\u002Fgithub.com\u002Fcommercelayer\u002Fcommercelayer-js-auth",{"_modelApiKey":366,"copy":408,"listStyle":384,"darkTheme":11,"buttons":409,"color":370,"indent":11},"\u003Ch4>Sales channel with guest and customer flows\u003C\u002Fh4>\n\n\u003Cp>Storefronts usually start with a guest token and later switch to a customer token when someone signs in. With the sales channel helper, this transition — and the underlying token storage — is handled for you.\u003C\u002Fp>\n",[],{"_modelApiKey":411,"code":412,"showLineNumbers":11,"highlightLines":280,"language":413,"size":414},"code_block","import {\n  authenticate,\n  makeSalesChannel,\n  type Storage,\n  type StorageValue,\n} from \"@commercelayer\u002Fjs-auth\"\n\n\u002F**\n * A valid storage must implement the `Storage` interface\n *\u002F\nfunction memoryStorage(): Storage {\n  const store: Record\u003Cstring, StorageValue> = {}\n  return {\n    async getItem(key) {\n      return store[key] ?? null\n    },\n    async setItem(key: string, value: StorageValue) {\n      store[key] = value\n    },\n    async removeItem(key: string) {\n      delete store[key]\n    },\n  }\n}\n\nconst salesChannel = makeSalesChannel(\n  {\n    clientId: \"\u003Cyour_client_id>\",\n    scope: \"\u003Cyour_scope>\",\n    debug: true, \u002F\u002F useful to understand what happens behind the scene\n  },\n  {\n    storage: memoryStorage(),\n  },\n)\n\n\u002F**\n * At the beginning, you'll get a guest token\n *\u002F\nconst authorization1 = await salesChannel.getAuthorization()\n\nconsole.log(\"Guest access token:\", authorization1.accessToken)\n\n\u002F**\n * At some point, a customer logs in\n *\u002F\nconst customerAuth = await authenticate(\"password\", {\n  clientId: \"\u003Cyour_client_id>\",\n  scope: \"\u003Cyour_scope>\",\n  username: \"\u003Ccustomer_email>\",\n  password: \"\u003Ccustomer_password>\",\n})\n\n\u002F**\n * After customer login, set the customer token (+ optional refreshToken)\n *\u002F\nawait salesChannel.setCustomer({\n  accessToken: customerAuth.accessToken,\n  refreshToken: customerAuth.refreshToken, \u002F\u002F optional for \"remember me\"\n  scope: customerAuth.scope,\n})\n\n\u002F**\n * After setting the customer, you'll get a customer token\n *\u002F\nconst authorization2 = await salesChannel.getAuthorization()\n\nconsole.log(\"Customer access token:\", authorization2.accessToken)\n\n\u002F**\n * Logout (revokes and clears storage for customer)\n *\u002F\nawait salesChannel.logoutCustomer()\n\n\u002F**\n * After logout, you'll get the previous guest token or a new one if expired\n *\u002F\nconst authorization3 = await salesChannel.getAuthorization()\n\nconsole.log(\"Guest access token after logout:\", authorization3.accessToken)","typescript","Wide",{"_modelApiKey":366,"copy":416,"listStyle":384,"darkTheme":11,"buttons":417,"color":370,"indent":11},"\u003Cp>As you can see, whenever you&#39;ll need an access token, you&#39;ll simply call \u003Ccode>getAuthorization()\u003C\u002Fcode>.\u003C\u002Fp>\n\n\u003Cp>Behind the scenes, this method checks for a valid customer token in storage first, then falls back to a guest token. If neither exists or both are expired, it automatically requests a new guest token.\u003C\u002Fp>\n",[],{"_modelApiKey":366,"copy":419,"listStyle":384,"darkTheme":11,"buttons":420,"color":370,"indent":11},"\u003Ch4>Integration token with composite storage\u003C\u002Fh4>\n\n\u003Cp>Backend jobs, webhooks, and admin tasks rely on integration tokens, so caching matters. A composite storage setup lets you fall back gracefully between fast memory and persistent Redis:\u003C\u002Fp>\n",[],{"_modelApiKey":411,"code":422,"showLineNumbers":11,"highlightLines":280,"language":413,"size":414},"import {\n  createCompositeStorage,\n  makeIntegration,\n} from \"@commercelayer\u002Fjs-auth\"\n\n\u002F**\n * The `Storage` interface is fully-compatible with the `unstorage` library.\n *\u002F\n\nimport { createStorage } from \"unstorage\"\nimport memoryDriver from \"unstorage\u002Fdrivers\u002Fmemory\"\nimport redisDriver from \"unstorage\u002Fdrivers\u002Fredis\"\n\nconst memoryStorage = createStorage({\n  driver: memoryDriver(),\n})\n\nconst redisStorage = createStorage({\n  driver: redisDriver({\n    url: \"\u003Cyour_redis_connection_string>\",\n  }),\n})\n\nconst compositeStorage = createCompositeStorage([\n  memoryStorage,\n  redisStorage,\n])\n\nconst integration = makeIntegration(\n  {\n    clientId: \"\u003Cyour_client_id>\",\n    clientSecret: \"\u003Cyour_client_secret>\",\n    debug: true,\n  },\n  {\n    storage: compositeStorage,\n  },\n)\n\n\u002F**\n * If you already requested an access token before,\n * now you'll probably get it from memory or Redis if not expired.\n * Otherwise, a new one will be requested.\n *\u002F\nconst authorization1 = await integration.getAuthorization()\n\nconsole.log(\"Integration access token #1:\", authorization1.accessToken)\n\n\u002F**\n * Subsequent calls will return the cached token from memory storage.\n *\u002F\nconst authorization2 = await integration.getAuthorization()\n\nconsole.log(\"Integration access token #2:\", authorization2.accessToken)\n\n\u002F**\n * Revoke the current integration authorization.\n * This will remove the authorization from memory and storage, and revoke the access token.\n *\u002F\nawait integration.revokeAuthorization()",{"_modelApiKey":366,"copy":424,"listStyle":384,"darkTheme":11,"buttons":425,"color":370,"indent":11},"\u003Ch3>Conclusion\u003C\u002Fh3>\n\n\u003Cp>Understanding authentication in Commerce Layer starts with recognizing how each credential defines access, who the request represents, and what actions it can perform. Whether it is a guest browsing a storefront, a logged-in customer, or a backend integration managing data, every token carries a specific purpose and scope.\u003C\u002Fp>\n\n\u003Cp>By managing token lifespans carefully and caching tokens efficiently, you can keep your applications both secure and performant. The new API‑credentials-based model in Commerce Layer JS Auth \u003Cstrong>v7\u003C\u002Fstrong> abstracts much of this complexity, giving you a robust, production‑ready authentication workflow out of the box.\u003C\u002Fp>\n\n\u003Cp>If your project still uses \u003Cstrong>v6\u003C\u002Fstrong>, plan to upgrade to \u003Cstrong>v7\u003C\u002Fstrong> to benefit from these improvements. The latest version is designed to reflect how teams actually cache tokens in production environments. With this new update, you can focus less on token handling and more on building seamless, secure experiences.\u003C\u002Fp>\n",[],{"_modelApiKey":427,"displayTitle":280,"copy":280,"cta":302,"ctaText":280,"faqsList":428},"faqs_block",[429],{"displayTitle":430,"faqs":431},"Key takeaways",[432,435,438,441,444],{"question":433,"answer":434},"Use the right token for the right job.","Integration tokens give you full access to *everything*, while sales channel tokens are scoped to a specific market. Choose wisely: if you're building a storefront, use a sales channel token so customers only see what's relevant to them (prices in their currency, available SKUs in their region).\n\nWhen a customer logs in, authenticate with their username and password to get a customer token. This unlocks personalized data like order history, saved addresses, and payment methods.",{"question":436,"answer":437},"Always cache your tokens.","Authentication requests are rate-limited, making caching essential. The examples above demonstrate how to implement caching with the new API credentials approach. Use cookies for browsers, Redis or KV stores for servers, and the composite storage pattern for multi-layer caching.\n\nOur JS Auth library handles the complexity: `getAuthorization()` checks the cache first and only requests a new token when necessary.",{"question":439,"answer":440},"Tokens can be revoked.","Tokens can be revoked before expiration (for example, to roll back a configuration mistake).\n\nWe don't have an endpoint to check whether the token has been revoked or not. When you consume the token, you'll know if the token is valid and if it can be used against that endpoint; otherwise, you'll get an `INVALID_TOKEN` error.\n\nHandle this gracefully by catching the exception, removing the invalid token from storage, and requesting a fresh one. This ensures your application recovers automatically from revoked tokens.",{"question":442,"answer":443},"Keep token lifespans short.","Setting integration tokens to last months or years might seem convenient, but it creates significant security risks. Stick with short lifespans (2-4 hours) and automatic refresh mechanisms. With **v7**'s storage helpers, token refresh is transparent. You never have to think about it.",{"question":445,"answer":446},"Consider SSO for customer authentication.","If you haven't implemented **Single Sign-On (SSO)** yet, it's worth exploring. SSO simplifies customer authentication, improves security, and provides a better user experience. About that, check out [our guide](\u002Fblog\u002Fsingle-sign-on-with-commerce-layer-using-next-js-and-auth0) on how to implement SSO using Next.js and Auth0 to get started.",[448,449,451,453,455,457,459,461,463,465,467,469,471,473,475,477,479],{"attributes":302,"tag":303,"content":304},{"attributes":450,"tag":308,"content":302},{"property":307,"content":304},{"attributes":452,"tag":308,"content":302},{"name":311,"content":304},{"attributes":454,"tag":308,"content":302},{"name":314,"content":315},{"attributes":456,"tag":308,"content":302},{"property":318,"content":315},{"attributes":458,"tag":308,"content":302},{"name":321,"content":315},{"attributes":460,"tag":308,"content":302},{"property":324,"content":325},{"attributes":462,"tag":308,"content":302},{"property":328,"content":329},{"attributes":464,"tag":308,"content":302},{"property":332,"content":333},{"attributes":466,"tag":308,"content":302},{"name":336,"content":325},{"attributes":468,"tag":308,"content":302},{"property":339,"content":340},{"attributes":470,"tag":308,"content":302},{"property":343,"content":344},{"attributes":472,"tag":308,"content":302},{"property":347,"content":348},{"attributes":474,"tag":308,"content":302},{"property":351,"content":352},{"attributes":476,"tag":308,"content":302},{"property":355,"content":280},{"attributes":478,"tag":308,"content":302},{"name":358,"content":359},{"attributes":480,"tag":308,"content":302},{"name":362,"content":363},[482],{"name":285,"picture":483},{"url":287,"alt":288,"title":288,"width":289,"height":289,"format":290,"focalPoint":484,"customData":485},{"x":292,"y":292},{},1791534732199]