Repository navigation
Authentication
Selldone customers sign in without a password, using a one-time password (OTP) sent by email or SMS. Customers do not need to register first: the first successful login creates their customer account in the shop. This page covers both OTP flows under window.$storefront.auth, how to store the returned access token, how to load the signed-in customer, and how to log out.
| Namespace | Methods | Endpoints (XAPI) |
|---|---|---|
auth.email |
requestOtp(email), verifyOTP(email, verification_code, source)
|
POST /shops/@{shop}/email-login/request, /verify
|
auth.sms |
requestOTP(dial_code, country_code, phone), verifyOTP(dial_code, country_code, phone, verification_code, source), selectUser(code, source), registerUser(code, name, email, password, no_email_mode, source)
|
POST /shops/@{shop}/sms-login/request, /verify, /select-user, /new-user
|
auth |
logout() |
POST /shops/@{shop}/logout |
user |
fetchMyInfo(onSuccess, onError) |
GET /me |
source is a Customer.Source value from Selldone Core: "customer" (default) or "vendor" (for marketplace vendors signing in to their panel).
import { Customer } from "@selldone/core-js/models";
Customer.Source.CUSTOMER; // "customer"Step 1. Request an OTP. Selldone emails a code to the address.
window.$storefront.auth.email
.requestOtp(email)
.then(({ success, email }) => {
// Show the "enter code" step
})
.catch((error) => console.error(error));Step 2. Verify the OTP and receive an access token.
window.$storefront.auth.email
.verifyOTP(email, otp, "customer")
.then(({ token, expires_in }) => {
saveCustomerToken(token, expires_in); // See "Store the access token" below
})
.catch((error) => console.error(error));| Response | Fields |
|---|---|
requestOtp |
success: boolean, email: string
|
verifyOTP |
token: string, expires_in: string (seconds until the token expires) |
Step 1. Request an OTP with the country dial code, the ISO country code and the phone number.
window.$storefront.auth.sms
.requestOTP("+1", "US", "5551234567")
.then(({ success, phone }) => {
// Show the "enter code" step (the official Storefront uses a 60-second resend timer)
});Step 2. Verify the OTP. The response method tells you what happens next:
method |
Meaning | Extra fields |
|---|---|---|
"login" |
Exactly one account uses this phone. You are signed in. |
token, expires_in
|
"select" |
Several accounts share this phone. Ask the customer to pick one. | users: { id, name, email, code }[] |
"register" |
New customer. Ask for a name (and optionally email and password). | code |
const res = await window.$storefront.auth.sms.verifyOTP(
"+1", "US", "5551234567", "123456", "customer",
);
if (res.method === "login") {
saveCustomerToken(res.token, res.expires_in);
} else if (res.method === "select") {
showAccountPicker(res.users); // each user has a `code`
} else if (res.method === "register") {
showRegisterForm(res.code);
}The Method enum is exported as XapiAuthSMSVerifyOtpTypes.Method (REGISTER, SELECT, LOGIN).
Step 3a. Select an account (when method === "select"), using the code of the chosen user:
const { token, expires_in } = await window.$storefront.auth.sms.selectUser(user.code, "customer");
saveCustomerToken(token, expires_in);Step 3b. Register a new customer (when method === "register"), using the code returned by verifyOTP:
const { token, expires_in } = await window.$storefront.auth.sms.registerUser(
code,
"Jane Doe", // name
"jane@example.com", // email (or null)
null, // password (or null)
false, // no_email_mode: true lets the customer skip the email
"customer",
);
saveCustomerToken(token, expires_in);For security and privacy, the email of a new SMS customer cannot be one that is already registered with Selldone. Providing an email is optional.
Note
The README inside auth/sms/ shows shorter, older signatures (for example requestOTP(phone)). The signatures on this page follow the current source code.
The OTP methods return a token but do not persist it. Store it the same way the official Storefront does in its window.SetToken() helper: save it in the access-token cookie (scoped to the shop prefix) and add it to the Authorization header. On the next page load, StorefrontSDK.Setup() reads the cookie and signs the customer in automatically.
function saveCustomerToken(token, expires_in) {
const expire_date = new Date(Date.now() + Number(expires_in) * 1000);
// Cookie name must match Setup()'s cookie_key_access_token option (default "access_token")
window.$cookies.set(
"access_token",
token,
expire_date.toUTCString(),
window.$storefront.prefix_url, // cookie path
undefined,
false,
);
window.axios.defaults.headers.common["Authorization"] = "Bearer " + token;
// Load the customer and refresh shop data (baskets, club, orders state)
window.$storefront.user.fetchMyInfo((user) => console.log("Signed in as", user.name));
window.$storefront.shop.fetchShop();
}window.$cookies is the cookie helper registered by SelldoneCore.Setup().
user.fetchMyInfo() uses callbacks (it is debounced by one second) and stores the result in window.$storefront.USER:
window.$storefront.user.fetchMyInfo(
(user) => {
// window.$storefront.USER === user
console.log(user.id, user.name, user.email_verified, user.profile);
},
(error) => {
// Token is invalid or expired: remove it
window.$cookies.remove("access_token", window.$storefront.prefix_url);
},
);Response fields (XapiUser.IMeServerResponse): id, name, phone, phone_verified, email_verified, personal_information_verified, subscribed, chips, profile, block_at, access. Responses with an HTTP status below 500 are treated as completed requests; when the body contains an error field, onError receives it, and network or server (5xx) errors also go to onError.
await window.$storefront.auth.logout(); // also sets window.$storefront.USER = null
window.$cookies.remove("access_token", window.$storefront.prefix_url);
delete window.axios.defaults.headers.common["Authorization"];The SDK wraps the email and SMS OTP flows. The official Storefront also offers other login modes configured per shop (for example OAuth providers), handled by the Storefront app and the Selldone platform rather than by this SDK. See ai-guideline/storefront/11-checkout-payment-account-deep-dive.md for how the official app handles them.
- Customer Account: currency, profile data and local preferences.
- Basket and Checkout: guest baskets and what changes after login.
- API Reference