Checkout Authentication¶
Customer authentication during checkout -- how Merchello handles email checks, sign-in, sign-up, guest checkout, password validation, and password resets.
What it is: A thin layer over Umbraco's member system scoped to the checkout flow. It creates/authenticates members, links them to the basket, and manages password-reset tokens — without forcing customers to leave the checkout page.
Why it exists: Standard ecommerce flows need all three of guest / sign-in / sign-up from one screen, plus a password-reset path that doesn't dump users back to a generic Umbraco login page. Merchello keeps these inside the checkout UI so conversion isn't broken by authentication detours.
Source: ICheckoutMemberService.cs, CheckoutApiController.cs, CheckoutPasswordResetController.cs.
Overview¶
Merchello's checkout supports three customer states:
- Guest checkout -- the customer provides an email but does not create an account.
- Sign in -- the customer has an existing Umbraco member account and signs in during checkout.
- Sign up -- the customer creates a new account during checkout.
All authentication operations are handled by ICheckoutMemberService and exposed through the checkout API.
Digital products always require an account. If the basket contains digital products, guest checkout is disabled (
CheckoutViewModel.HasDigitalProducts = true) and the customer must sign in or create an account. This is enforced server-side inCheckoutService.BasketHasDigitalProductsAsync()— do not rely on UI checks alone.
How It Works¶
Email Check¶
When a customer enters their email address at checkout, the frontend calls the check-email endpoint. For security, this endpoint always returns false for hasExistingAccount to prevent email enumeration attacks. The UI shows both sign-in and create-account options regardless.
Tip: Even though the API doesn't reveal whether an account exists, the sign-in form will surface errors if the credentials are wrong. This is the standard approach to prevent attackers from discovering which emails have accounts.
Sign In¶
Customers with an existing Umbraco member account can sign in during checkout:
The service calls ICheckoutMemberService.SignInAsync() which authenticates against Umbraco's member system. On success, the customer's member key is associated with the basket.
Sign Up (Create Account)¶
New customers can create an account during checkout. The account is created as an Umbraco member and the customer is automatically signed in:
When the address save request includes a password field, the service:
- Validates the password against Umbraco's configured password requirements
- Creates a new Umbraco member via
ICheckoutMemberService.CreateMemberAsync() - Assigns the member to the default checkout customer group
- Signs in the new member automatically
Guest Checkout¶
If the customer does not provide a password, they proceed as a guest. The email is saved with the basket for order communication, but no member account is created.
Warning: Guest checkout is automatically disabled when the basket contains digital products. The UI should check
hasDigitalProductson theCheckoutViewModeland enforce account creation.
Password Validation¶
Before creating an account, you can validate the password against Umbraco's rules:
The response includes whether the password is valid and any specific errors (too short, missing special characters, etc.). This lets you give real-time feedback as the customer types.
Password Reset¶
Merchello includes a complete password reset flow for customers who forget their password during checkout.
Step 1: Request a Reset¶
This calls ICheckoutMemberService.InitiatePasswordResetAsync(). The endpoint always returns success to prevent email enumeration -- even if the email doesn't exist, no error is shown.
If the email matches a member account, a reset token is generated and a notification is published (which triggers a reset email via your configured email handler).
Step 2: Validate the Token¶
When the customer clicks the reset link, they land on /checkout/reset-password?email=...&token=.... The CheckoutPasswordResetController validates the token on page load:
// The controller validates automatically on GET
var validation = await checkoutMemberService.ValidateResetTokenAsync(email, token, ct);
viewModel.TokenValid = validation.IsValid;
The reset page renders at ~/App_Plugins/Merchello/Views/Checkout/ResetPassword.cshtml.
Step 3: Submit New Password¶
{
"email": "customer@example.com",
"token": "the-reset-token",
"newPassword": "new-secure-password"
}
On success, the password is updated and the customer can sign in with their new credentials.
Logged-In Member Detection¶
When the checkout page loads, MerchelloCheckoutController checks if the customer is already logged in:
var currentMember = await memberManager.GetCurrentMemberAsync();
var isLoggedIn = currentMember != null;
The CheckoutViewModel exposes:
IsLoggedIn--trueif the customer is already authenticatedMemberEmail-- the logged-in member's email (auto-populates the email field)
If the customer is logged in, the UI should hide the "Create an account" and "Sign in" options since they're already authenticated.
ICheckoutMemberService Reference¶
The service interface provides all authentication operations:
| Method | Purpose |
|---|---|
CheckEmailAsync(email) |
Check if an email has an existing account |
ValidatePasswordAsync(password) |
Validate password against Umbraco rules |
SignInAsync(email, password) |
Sign in with existing account |
CreateMemberAsync(parameters) |
Create a new member and sign in |
GetOrEnsureMemberGroupAsync() |
Get/create the default customer member group |
GetMemberKeyByEmailAsync(email) |
Look up a member by email |
InitiatePasswordResetAsync(email) |
Start password reset flow |
ValidateResetTokenAsync(email, token) |
Validate a reset token |
ResetPasswordAsync(parameters) |
Complete password reset |
SignOutAsync() |
Sign out the current member |
Rate Limiting¶
Authentication endpoints are rate-limited to prevent abuse:
- Check email: 10 requests per minute per IP
- Password reset: 10 requests per minute per IP
If the limit is exceeded, the API returns 429 Too Many Requests.