Customer Accounts
In this document, you’ll learn how registered and unregistered accounts are distinguished in the Medusa application.
has_account Property#
The Customer data model has a has_account property, which is a boolean that indicates whether a customer is registered.
When a guest customer places an order, a new Customer record is created with has_account set to false.
When this or another guest customer registers an account with the same email, a new Customer record is created with has_account set to true.
Email Uniqueness#
The above behavior means that two Customer records may exist with the same email address. However, the main difference is the has_account property's value.
So, there can only be one guest customer (having has_account=false) and one registered customer (having has_account=true) with the same email address.
Change a Guest Customer to a Registered Customer#
You can only set the has_account property when you create a customer. The updateCustomersWorkflow and the Customer Module's updateCustomers method don't accept it. So, you can't change an existing guest customer to a registered customer.
This affects flows that link a new auth identity to an existing guest customer. For example, a custom auth provider that sets the customer_id in the auth identity's app metadata to the guest customer's ID. The customer can log in, but the Medusa Admin still shows them as a guest.
Instead, use one of the following approaches.
Set has_account When Importing Customers#
If you're migrating customers from another platform, set has_account to true for customers that have accounts when you create them. How you do that depends on whether the customer's auth identity already exists at import time.
Auth Identity Exists
If you create the customer's auth identity before importing the customer, use the createCustomerAccountWorkflow. It creates the customer with has_account set to true and sets the customer's ID in the auth identity's app metadata.
For example, in a custom CLI script:
1import { ExecArgs } from "@medusajs/framework/types"2import {3 createCustomerAccountWorkflow,4} from "@medusajs/medusa/core-flows"5 6export default async function importCustomers({7 container,8}: ExecArgs) {9 await createCustomerAccountWorkflow(container).run({10 input: {11 authIdentityId: "authid_123",12 customerData: {13 email: "john@example.com",14 },15 },16 })17}
The workflow creates one customer per run, so run it for each customer you import.
Auth Identity Is Created on First Login
Some auth providers, such as passwordless providers, create the auth identity when the customer first logs in. In that case, create the customers with has_account set to true using the createCustomersWorkflow. It accepts multiple customers in one run:
1import { ExecArgs } from "@medusajs/framework/types"2import {3 createCustomersWorkflow,4} from "@medusajs/medusa/core-flows"5 6export default async function importCustomers({7 container,8}: ExecArgs) {9 await createCustomersWorkflow(container).run({10 input: {11 customersData: [12 {13 email: "john@example.com",14 has_account: true,15 },16 ],17 },18 })19}
Then, when the customer first logs in, link the new auth identity to the existing customer. Create a workflow that uses the setAuthAppMetadataStep to set the customer's ID in the auth identity's app metadata:
1import {2 createWorkflow,3 WorkflowResponse,4} from "@medusajs/framework/workflows-sdk"5import {6 setAuthAppMetadataStep,7} from "@medusajs/medusa/core-flows"8 9type LinkCustomerAuthIdentityInput = {10 authIdentityId: string11 customerId: string12}13 14export const linkCustomerAuthIdentityWorkflow = createWorkflow(15 "link-customer-auth-identity",16 (input: LinkCustomerAuthIdentityInput) => {17 const authIdentity = setAuthAppMetadataStep({18 authIdentityId: input.authIdentityId,19 actorType: "customer",20 value: input.customerId,21 })22 23 return new WorkflowResponse(authIdentity)24 }25)
Execute the workflow in your login flow after the auth provider creates the auth identity. The step throws an error if the auth identity is already linked to a customer.
Register a New Customer Account#
When a guest customer registers, use the createCustomerAccountWorkflow to create a registered customer with the same email. The workflow also sets the customer's ID in the auth identity's app metadata. It doesn't change the existing guest customer.
The guest customer's orders stay linked to the guest customer. To move them to the registered customer, the customer can request an order transfer using the Request Order Transfer API route.
Customer Deletion and Email Reuse#
When a merchant deletes a customer, the Customer record is soft-deleted, meaning it is not permanently removed from the database.
When using the Medusa Application with the Auth Module, possible confusion may arise in the following scenarios:
- An admin user is using the email address
john@example.com, and a customer tries to register with the same email address. - An admin user has deleted a customer with the email address
jane@example.com, and another customer tries to register with the same email address.
In these and similar scenarios, the customer trying to register will receive an error message indicating that the email address is already in use:
To resolve this, you can amend the registration flow to:
- Retrieve the login token of the existing identity with the same email address.
- Use the login token when registering the new customer. This will not remove the existing identity but will allow the new customer to register with the same email address.
You can learn more about how to implement this flow in the following guides:
- Conceptual guide on how to implement this flow with Medusa's authentication routes.
- How-to guide on how to implement this in a storefront.