hiko-social-login-react
v1.3.5
Published
HIKO Social Login react for Hydrogen integration
Maintainers
Readme
hiko-social-login-react
React bindings for HIKO Social Login — a Shopify social login app — for use in headless / Hydrogen storefronts.
The package ships two things:
SocialLoginWidget— a React component that mounts the HIKO login widget and streams customer state to your app via DOM events.hiko-social-login-react/sign— a tiny server-side helper for signing the Headless API (e.g. disconnecting a social provider).
Contents
Installation
npm i hiko-social-login-react --save
# or
yarn add hiko-social-login-reactPrerequisites
- Install the HIKO Social Login app on your shop.
- Install Headless to generate a public access token.
Quick start
import { useState, useEffect, useCallback, useRef } from "react";
import { SocialLoginWidget } from "hiko-social-login-react";
export function Login() {
const shop = "xxxx.myshopify.com";
const publicAccessToken = "<your Hydrogen public access token>";
const logoutRef = useRef(null);
const refreshRef = useRef(null);
const [customer, setCustomer] = useState(window.HIKO?.customer);
const handleHiko = useCallback((event) => {
if (["login", "activate", "multipass"].includes(event.detail.action))
setCustomer(event.detail.customer);
}, []);
useEffect(() => {
document.addEventListener("hiko", handleHiko);
return () => document.removeEventListener("hiko", handleHiko);
}, [handleHiko]);
if (customer)
return (
<ul>
{Object.keys(customer).map((key) => (
<li key={key}>
{key}: {String(customer[key])}
</li>
))}
</ul>
);
return (
<SocialLoginWidget
shop={shop}
publicAccessToken={publicAccessToken}
baseUrl="https://apps.hiko.link"
logout={(cb) => (logoutRef.current = cb)}
refresh={(cb) => (refreshRef.current = cb)}
/>
);
}A complete, runnable example lives in src/Demo.tsx.
SocialLoginWidget props
| Prop | Type | Required | Description |
| ------------------- | ------------------------ | -------- | --------------------------------------------------------------------------------------------------- |
| shop | string | yes | Shop domain, e.g. xxxx.myshopify.com. |
| publicAccessToken | string | yes | Hydrogen public access token generated by the Headless app. |
| baseUrl | string | yes | Origin that serves the HIKO widget script, e.g. https://apps.hiko.link. |
| logout | (cb: () => void) => void | yes | Registration callback — HIKO hands you a logout() function; call it to sign the customer out. |
| refresh | (cb: () => void) => void | yes | Registration callback — HIKO hands you a refresh() function; call it to reload the widget script. |
logout and refresh use a callback-registration pattern: you pass a setter, HIKO invokes it
with the real function, and you store that in a ref to call later (see src/Demo.tsx).
Customer state & events
The widget dispatches a DOM CustomEvent named hiko on document. Its event.detail carries an
action and, for auth actions, the customer:
| action | Meaning |
| --------------------------------- | ------------------------------------------- |
| login / activate / multipass | Customer authenticated — detail.customer is set. |
| click | Widget interaction (no customer change). |
The current customer is also available synchronously at window.HIKO?.customer after the script
loads.
Headless API
REST endpoints for headless / Hydrogen storefronts, served by the HIKO backend under
/apps/authapp/:action.
Authentication
Every headless request is authenticated by an HMAC-SHA256 signature over the query string,
keyed by the shop's Hydrogen public access token (the same publicAccessToken you pass to
SocialLoginWidget).
The signed message is every param except signature, keys sorted alphabetically and joined as
key=value pairs with & — a plain string with no URL-encoding and no leading ?. The
hex-encoded digest is sent as the signature param.
This package ships the signing helper so you don't have to reimplement it:
import { sign } from "hiko-social-login-react/sign";
const signature = sign(
{ customer_id: "gid://shopify/Customer/123", shop: "myshop.myshopify.com", social: "facebook" },
process.env.HYDROGEN_PUBLIC_ACCESS_TOKEN
);Failure modes: shop not installed / no public access token / missing signature → 400;
signature mismatch → 401.
Sign on the server. The public access token is a signing secret — never expose it in browser code. A storefront should call your own server route, which signs and forwards the request.
DELETE /apps/authapp/disconnect
Remove one social-provider connection from a customer. The customer profile is untouched; only the link to the named provider is deleted. Removing a connection does not revoke the token at the provider. The call is idempotent — safe to retry.
Query parameters
| Param | Required | Description |
| ------------- | -------- | ----------------------------------------------------------- |
| customer_id | yes | Shopify customer id or GID (normalized to GID server-side). |
| social | yes | Provider name, e.g. google, facebook, apple, line. |
| shop | yes | Shop domain, e.g. myshop.myshopify.com. |
| signature | yes | HMAC-SHA256 hex of the other params (see Authentication). |
Responses
200 OK
{ "customer_id": "gid://shopify/Customer/123", "social": "facebook", "removed": true }removed is false when the customer had no such connection (idempotent — safe to retry). A
well-formed but unrecognized social also returns removed: false rather than an error.
| Status | Meaning |
| ------ | ------------------------------------------------------------------------ |
| 400 | Missing customer_id, malformed social, shop not installed, no token. |
| 401 | Signature mismatch. |
| 404 | customer_id does not resolve to a Shopify customer. |
| 500 | Shopify API / database error. |
Example — Node.js
import { sign } from "hiko-social-login-react/sign";
const SHOP = "myshop.myshopify.com";
const PUBLIC_ACCESS_TOKEN = process.env.HYDROGEN_PUBLIC_ACCESS_TOKEN;
const BASE = `https://${SHOP}`; // or the app proxy host
async function disconnectSocial(customerId, social) {
const params = { customer_id: customerId, shop: SHOP, social };
const signature = sign(params, PUBLIC_ACCESS_TOKEN);
const query = new URLSearchParams({ ...params, signature }).toString();
const res = await fetch(`${BASE}/apps/authapp/disconnect?${query}`, {
method: "DELETE",
});
if (!res.ok) {
const { error } = await res.json().catch(() => ({}));
throw new Error(`disconnect failed (${res.status}): ${error ?? "unknown"}`);
}
return res.json(); // { customer_id, social, removed }
}
// Remove the logged-in customer's Facebook link
await disconnectSocial("gid://shopify/Customer/123", "facebook");Testing
npm testUnit tests (Vitest) cover the request-signing helper — deterministic digests, alphabetical key
ordering, exclusion of the signature param, and no URL-encoding of values. See
src/sign.test.ts.
Links
- HIKO Social Login on the Shopify App Store
- Headless app (generates the public access token)
- Demo source
