Skip to content
Last updated

Customer Accounts and Login in Norce Commerce

This guide explains how to implement customer login and account management in a frontend application using Norce Commerce Services. It covers common scenarios, best practices, and technical details for handling customer data, authentication, and password management.

Overview

Norce Commerce provides basic account management and password validation. Each account is linked to a Customer object, which can be used for segmentation, pricing, and offers.

Note:
If you use a third-party authentication provider, you do not need Norce accounts. Instead, match the authenticated identity to a Norce customer using the email address or CustomerCode.

This document focuses on scenarios where Norce Commerce manages the account information.


Customer Object Example

Below are example representations of a customer in JSON and XML formats. These examples include both individual and company-related fields.

Example Customer (without company)
{
  "Id": 3710298,
  "Key": "264148a6-9c4c-4f7c-827b-8c43ac72a852",
  "Code": "cust0043",
  "Email": "test0043@tester.com",
  "SSN": null,
  "FirstName": "Test person 0043",
  "LastName": null,
  "Phone": null,
  "CellPhone": null,
  "ReferId": null,
  "ReferUrl": null,
  "Account": {
    "Id": 2095010,
    "Key": "f4026524-39b5-43fe-93b3-63da483a7597",
    "LoginName": "test0043@tester.com",
    "Name": "Test person 0043",
    "Roles": [
      43
    ],
    "Authorizations": [],
    "IsActive": true
  },
  "Companies": [
    {
      "Id": 334815,
      "Key": "85abed80-7c24-4d26-8f4f-5ad96ca0f222",
      "Code": "test0043",
      "Name": "Test kund 0043",
      "OrgNo": null,
      "Phone": null,
      "ReferId": null,
      "ReferUrl": null,
      "DeliveryAddresses": [],
      "InvoiceAddress": {
        "Id": 11115165,
        "CareOf": null,
        "Line1": "Testgatan 1",
        "Line2": null,
        "Zip": "123 45",
        "City": "Stockholm",
        "CountryId": 0,
        "Country": null,
        "Region": null,
        "IsValidated": false,
        "GlobalLocationNo": null,
        "ShippingPhoneNumber": null
      },
      "UseInvoiceAddressAsDeliveryAddress": false,
      "Info": [
        {
          "Id": 267,
          "Value": "",
          "Code": "A1"
        }
      ],
      "PricelistIds": [],
      "ParentId": null,
      "DeliveryMethodIds": [],
      "PaymentMethodIds": [],
      "Email": null,
      "Flags": [
        {
          "Id": 118,
          "Name": "Bronskund",
          "Group": 37,
          "IsSelected": true
        }
      ],
      "VatNo": null
    }
  ],
  "DeliveryAddresses": [],
  "InvoiceAddress": {
    "Id": 2608019,
    "CareOf": null,
    "Line1": null,
    "Line2": null,
    "Zip": null,
    "City": null,
    "CountryId": 0,
    "Country": null,
    "Region": null,
    "IsValidated": false,
    "GlobalLocationNo": null,
    "ShippingPhoneNumber": null
  },
  "Flags": [
    {
      "Id": 117,
      "Name": "Silverkund",
      "Group": 37,
      "IsSelected": true
    }
  ],
  "UseInvoiceAddressAsDeliveryAddress": false,
  "Info": [
    {
      "Id": 237,
      "Value": "",
      "Code": "Xtra1"
    }
  ],
  "PricelistIds": [],
  "CrmId": null,
  "IsActive": true,
  "Created": "/Date(1583484623047+0100)/",
  "Updated": "/Date(1583484785267+0100)/"
}

<Customer xmlns="Enferno.Services.Contracts.Expose.Customers" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
    <Id>3710298</Id>
    <Key>264148a6-9c4c-4f7c-827b-8c43ac72a852</Key>
    <Code>cust0043</Code>
    <Email>test0043@tester.com</Email>
    <SSN i:nil="true"/>
    <FirstName>Test person 0043</FirstName>
    <LastName i:nil="true"/>
    <Phone i:nil="true"/>
    <CellPhone i:nil="true"/>
    <ReferId i:nil="true"/>
    <ReferUrl i:nil="true"/>
    <Account>
        <Id>2095010</Id>
        <Key>f4026524-39b5-43fe-93b3-63da483a7597</Key>
        <LoginName>test0043@tester.com</LoginName>
        <Name>Test person 0043</Name>
        <Roles xmlns:a="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
            <a:int>43</a:int>
        </Roles>
        <Authorizations xmlns:a="Enferno.Services.Contracts.Expose"/>
        <IsActive>true</IsActive>
    </Account>
    <Companies>
        <Company>
            <Id>334815</Id>
            <Key>85abed80-7c24-4d26-8f4f-5ad96ca0f222</Key>
            <Code>test0043</Code>
            <Name>Test kund 0043</Name>
            <OrgNo i:nil="true"/>
            <Phone i:nil="true"/>
            <ReferId i:nil="true"/>
            <ReferUrl i:nil="true"/>
            <DeliveryAddresses/>
            <InvoiceAddress>
                <Id>11115165</Id>
                <CareOf i:nil="true"/>
                <Line1>Testgatan 1</Line1>
                <Line2 i:nil="true"/>
                <Zip>123 45</Zip>
                <City>Stockholm</City>
                <CountryId>0</CountryId>
                <Country i:nil="true"/>
                <Region i:nil="true"/>
                <IsValidated>false</IsValidated>
                <GlobalLocationNo i:nil="true"/>
                <ShippingPhoneNumber i:nil="true"/>
            </InvoiceAddress>
            <UseInvoiceAddressAsDeliveryAddress>false</UseInvoiceAddressAsDeliveryAddress>
            <Info xmlns:a="Enferno.Services.Contracts.Expose">
                <a:Item>
                    <a:Id>267</a:Id>
                    <a:Value/>
                    <a:Code>A1</a:Code>
                </a:Item>
            </Info>
            <PricelistIds xmlns:a="http://schemas.microsoft.com/2003/10/Serialization/Arrays"/>
            <ParentId i:nil="true"/>
            <DeliveryMethodIds xmlns:a="http://schemas.microsoft.com/2003/10/Serialization/Arrays"/>
            <PaymentMethodIds xmlns:a="http://schemas.microsoft.com/2003/10/Serialization/Arrays"/>
            <Email i:nil="true"/>
            <Flags>
                <Flag>
                    <Id>118</Id>
                    <Name>Bronskund</Name>
                    <Group>37</Group>
                    <IsSelected>true</IsSelected>
                </Flag>
            </Flags>
            <VatNo i:nil="true"/>
        </Company>
    </Companies>
    <DeliveryAddresses/>
    <InvoiceAddress>
        <Id>2608019</Id>
        <CareOf i:nil="true"/>
        <Line1 i:nil="true"/>
        <Line2 i:nil="true"/>
        <Zip i:nil="true"/>
        <City i:nil="true"/>
        <CountryId>0</CountryId>
        <Country i:nil="true"/>
        <Region i:nil="true"/>
        <IsValidated>false</IsValidated>
        <GlobalLocationNo i:nil="true"/>
        <ShippingPhoneNumber i:nil="true"/>
    </InvoiceAddress>
    <Flags>
        <Flag>
            <Id>117</Id>
            <Name>Silverkund</Name>
            <Group>37</Group>
            <IsSelected>true</IsSelected>
        </Flag>
    </Flags>
    <UseInvoiceAddressAsDeliveryAddress>false</UseInvoiceAddressAsDeliveryAddress>
    <Info xmlns:a="Enferno.Services.Contracts.Expose">
        <a:Item>
            <a:Id>237</a:Id>
            <a:Value/>
            <a:Code>Xtra1</a:Code>
        </a:Item>
    </Info>
    <PricelistIds xmlns:a="http://schemas.microsoft.com/2003/10/Serialization/Arrays"/>
    <CrmId i:nil="true"/>
    <IsActive>true</IsActive>
    <Created>2020-03-06T09:50:23.047</Created>
    <Updated>2020-03-06T09:53:05.267</Updated>
</Customer>

Creating a Customer and Account

Scenario: A user initiates account creation, either during checkout or by choosing to become a member.

Process:

  1. Collect personal information from the user.
  2. Call the Norce Commerce Customer Service method RegisterCustomer3 with:
    • A password string.
    • A Customer object containing an Account object (required for account functionality).
  3. Norce returns a new Customer object with an Account and internal Id. Store this information securely.
  4. Send a confirmation email to the customer, either via your backend or using Norce's built-in functionality.

Create Account Illustration: Account creation process

Note:
Norce does not validate password strength. Implement password validation in your backend.

Technical Note:
Passwords are securely hashed before storage in Norce.


Customer Login

To authenticate a user:

  1. Call the LoginPost method with accountname and password.
  2. If credentials are correct, a Customer object is returned. Add this to the session and save to a cookie.
  3. If authentication fails, an exception is returned. See the API reference for error details.

Login Illustration: Login process


Returning Users (Session Persistence)

When a user revisits the site and is already logged in (e.g., via a cookie with accountId):

  1. Retrieve the accountId from the cookie.
  2. Call GetCustomerByAccountId.
  3. If the account is valid, a Customer object is returned. If not, null is returned.

Revisit Illustration: Returning user session


Forgotten or Changing Password

Scenario: The user has forgotten their password or wants to change it.

Process:

  1. User provides account information (email, customer code, or login name).
  2. Backend fetches the Customer object using one of:
  3. Backend generates an email with an encrypted link containing the account name and a validity timestamp.
  4. User clicks the link, which is decrypted and validated. User is prompted for a new password.
  5. Backend calls UpdateCustomer3 with the Customer object and new password.

Forgotten password Illustration: Password reset process

Note:
Customer emails must be unique within Norce. Uniqueness can be scoped to the client or application.


When sending password reset links, encrypt the information to avoid exposing sensitive data. Below is a C# example for creating and resolving secure links:

C# Example: Password Reset Link
public class PasswordResetHelper
{
    /// <summary>
    /// Create the clickable link to send to the users registered email
    /// The current timestamp is part of the token
    /// </summary>
    public string CreateLinkToTheMail(string loginName)
    {
        var token = $"{account.LoginName}|{DateTime.Now}";
        token = RijndaelEncryption.EncryptToUrl(token);
        return $"{PathHelper.FullBaseUrl()}login;token={token}";
    }

    /// <summary>
    /// Resolve the login name from the token in the link.
    /// </summary>
    /// <returns>LoginName</returns>
    public string ResolveLinkFromMail(string token)
    {
        token = RijndaelEncryption.DecryptFromUrl(token);
        var parts = token.Split('|');
        if (parts.Length != 2)
            throw new Exception("Bad token");
        var accountName = parts[0];
        DateTime date;
        if (!DateTime.TryParse(parts[1], out date))
        {
            throw new Exception("Bad token");
        }
        if (DateTime.Now - date > TimeSpan.FromHours(24))
        {
            throw new Exception("Change password mail is older than 24 hours.");
        }
        return accountName;
    }
}

Suggested further reading