Skip to content

Instantly share code, notes, and snippets.

@magicspon
Forked from jorgemasta/sso-login.ts
Last active April 20, 2023 09:19
Show Gist options
  • Save magicspon/93f42be4395702db8ec006e9cb6236b2 to your computer and use it in GitHub Desktop.
Save magicspon/93f42be4395702db8ec006e9cb6236b2 to your computer and use it in GitHub Desktop.
SSO Login to BigCommerce using a (Next) API Route
import type { NextApiHandler, NextApiRequest, NextApiResponse } from 'next'
import jwt from 'jsonwebtoken';
import {v4 as uuidv4} from 'uuid';
import concatHeader from '../utils/concat-cookie'
import getConfig from '../utils/get-config'
function getSsoLoginUrl(customerId: number, storeHash: string, storeUrl: string, clientId: string, clientSecret: string) {
const dateCreated = Math.round((new Date()). getTime() / 1000);
const payload = {
"iss": clientId,
"iat": dateCreated,
"jti": uuidv4(),
"operation": "customer_login",
"store_hash": storeHash,
"customer_id": customerId,
"redirect_to": "/"
}
let token = jwt.sign(payload, clientSecret, { algorithm:'HS256' });
return `${storeUrl}/login/token/${token}`;
};
function getCookie(header: string | null, cookieKey: string) {
if (!header) return null
const cookies : string[] = header.split(/, (?=[^;]+=[^;]+;)/)
return cookies.find(cookie => cookie.startsWith(`${cookieKey}=`))
}
function externalAuthProvider() {
// Auth the user against an external auth provider
// It should return a BigCommerce customer ID
return { customerId: 157 }
}
const ssoLoginApi : NextApiHandler = async (request, response) => {
const config = getConfig()
const { customerId } = externalAuthProvider()
const ssoLoginUrl = getSsoLoginUrl(customerId, config.storeHash, config.storeUrl, config.clientId, config.clientSecret)
const { headers } = await fetch(ssoLoginUrl, {
redirect: "manual" // Important!
})
// Set-Cookie returns several cookies, we only want SHOP_TOKEN
let shopToken = getCookie(setCookie, "SHOP_TOKEN")
let perfToken = getCookie(setCookie, "Shopper-Pref")
let sessionToken = getCookie(setCookie, "SHOP_SESSION_TOKEN")
if (shopToken && typeof shopToken === 'string') {
const { host } = request.headers
// OPTIONAL: Set the cookie at TLD to make it accessible on subdomains (embedded checkout)
shopToken += `; Domain=${host?.includes(":") ? host?.slice(0, host.indexOf(":")) : host}`
perfToken += `; Domain=${host?.includes(":") ? host?.slice(0, host.indexOf(":")) : host}`
sessionToken += `; Domain=${host?.includes(":") ? host?.slice(0, host.indexOf(":")) : host}`
// In development, don't set a secure shopToken or the browser will ignore it
if (process.env.NODE_ENV !== 'production') {
shopToken = shopToken.replace(/; Secure/gi, '')
// console.log('shopToken_replaced', shopToken)
// SameSite=none can't be set unless the shopToken is Secure
// bc seems to sometimes send back SameSite=None rather than none so make
// this case insensitive
shopToken = shopToken.replace(/; SameSite=none/gi, '; SameSite=lax')
}
const shopCookie = concatHeader(res.getHeader("Set-Cookie"), shopToken)
const perfCookie = concatHeader(res.getHeader("Set-Cookie"), perfToken)
const sessionCookie = concatHeader(res.getHeader("Set-Cookie"),sessionToken)
response.setHeader(
'Set-Cookie',
[shopCookie, perfCookie, sessionCookie]
)
return response.status(200).json({ result: "success" })
}
return response.status(500).json({ error: "Invalid authentication" })
}
export default ssoLoginApi
@Manya2112
Copy link

I'd recommend using miniOrange BigCommerce SSO solution rather than building your own due to following imp reasons:

  1. Time and Cost Savings: Building your own SSO solution can be time-consuming and expensive. With miniOrange, you can quickly and easily implement SSO for your BigCommerce site without the need for additional resources or development time.
  2. Security and Reliability: miniOrange provides a secure and reliable SSO solution that uses industry-standard protocols and encryption methods. This helps ensure that your user's data is protected and that your SSO solution is always available.
  3. Customization: miniOrange provides several customization options, including the ability to customize the login form, authentication methods, and branding to match your business needs.
  4. Support and Maintenance: With miniOrange, you have access to a dedicated support team that can assist with any issues or questions that may arise. Additionally, miniOrange provides ongoing maintenance and updates to ensure that your SSO solution remains up-to-date and secure.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment