# Working with Customers and the login process Norce Commerce can help when developing login functionality in your front end application. It is not a full-fledged identity provider but has the ability to store and manage accounts and validate passwords for you. The accounts in Norce will be associated with the Customer object that can be used for segmentation and specific pricing or offers. - Read more on that in the [Norce Commerce user documentation](/user-portal/user-landing). - Check out the examples in [Postman](https://documenter.getpostman.com/view/2973406/2sA35MzK14#6e0b7951-1d65-4bd5-93a7-1ed0875f984c) as well. Note When using other solutions than Norce's for the authentication functionality, there are other aspects to think about, you won't need any accounts in Norce, instead you just look up the correct customer in Norce after the login process is finished. Use the email address or `CustomerCode` to match an identity from the third party authenticator. But this document explains the common scenarios for handling the account information in Norce Commerce Services. [The full Customer Schema](/api-reference/schemas/customer#customer) details summary An example customer (without company) ```JSON { "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)/" } ``` ```XML 3710298 264148a6-9c4c-4f7c-827b-8c43ac72a852 cust0043 test0043@tester.com Test person 0043 2095010 f4026524-39b5-43fe-93b3-63da483a7597 test0043@tester.com Test person 0043 43 true 334815 85abed80-7c24-4d26-8f4f-5ad96ca0f222 test0043 Test kund 0043 11115165 Testgatan 1 123 45 Stockholm 0 false false 267 A1 118 Bronskund 37 true 2608019 0 false 117 Silverkund 37 true false 237 Xtra1 true 2020-03-06T09:50:23.047 2020-03-06T09:53:05.267 ``` ## Create Customer and Account ![Create Account](/assets/create-customer-and-account-new.8293ba40b76aba8cd6ab3a34c002a0c12a065956272abfcf7853b6d78a03c13d.afe294b5.png) 1. A user choice or action starts the scenario, either from a checkout process or a decision to become a "member" in the site. 2. After asking for personal information the back-end calls Norce Commerce´s Customer Service method [RegisterCustomer3](/api-reference/services/customerservice/openapi/customers/registercustomer3). Norce takes a `password` string, a `Customer` object with an `Account` object (otherwise only the customer is created and no account functionality is possible) and returns a new `Customer` object with `Account` and its internal `Id` that should be stored in a persisted way. 3. And a recommended practice is to send a confirmation email at this stage to the customer, or use Norce's build in functionality for that. Note Norce does not validate password strength, this must be done in the backend. Technical Note Passwords are stored in Norce after being securely hashed to ensure they cannot be recognized. ## Login ![Login](/assets/login-new.b7d1d5ca73a19997d5bef67103407872bc39469ba7c471d4fc2de8c26a1332a8.afe294b5.png) To login, you only need to call the [LoginPost](/api-reference/services/customerservice/openapi/accounts/loginpost) method in Norce Commerce, passing in `accountname` and `password`. If credentials is correct a `Customer` object is returned the user is authenticated and can be added to the session and saved to a cookie. Otherwise, you get an exception. See api Reference documentation on the supported errors. ## Re-visit the site (already logged in) ![Revisit](/assets/re-visit-the-site-already-logged-in-new.ba5c99b064436b69504af61e95387c48b3b40aac02fb0c8d41811bb7a0dafb8e.afe294b5.png) When a user revisits a site where they are already logged in, and the `accountId` is saved in a persisted way, for example in a cookie. Resolve the `accountId` from the cookie and call [GetCustomerByAccountId](/api-reference/services/customerservice/openapi/customers/getcustomerbyaccountid). The method returns a `Customer` object if everything is alright and `null` if the account has been disabled or does not exist. ## Forgotten password (or change a password) ![Forgotten password](/assets/forgotten-password-or-change-a-password-new.6f772359fb869204597ff3324cb59dbb7d004f5f4e2700d775c72325ec90b319.afe294b5.png) 1. When the user has forgotten their password they visit a page where they provide some account information. It could be the email address, customer code or the login name. 2. The back-end calls Norce Commerce Customer Service to fetch the `Customer` object. Use [GetCustomerByEmail](/api-reference/services/customerservice/openapi/customers/getcustomerbyemail), [GetCustomerByCode](/api-reference/services/customerservice/openapi/customers/getcustomerbycode) or [GetCustomerByLoginName](/api-reference/services/customerservice/openapi/customers/getcustomerbyloginname) depending on what data provided by the user. The methods will return the `Customer` object, if it exists and is not disabled. 3. Your backend generate an email with an encrypted link, containing account name and a valid to timestamp (determines how long will the link be valid) 4. The user click on the link in the email and lands on a page where the link information is decrypted and validated. The user is asked for a new password. 5. The backend calls Norce and updates the password. The method is [UpdateCustomer3](/api-reference/services/customerservice/openapi/customers/updatecustomer3). Pass in the `Customer` object and the new `password` string. Note Customer emails must be unique in Norce. It is not allowed to have two customers with the same email within the same client or application. (There is a setting to define the scope of uniqueness: customers can either be shared across all applications or be unique within each application.) ### Notification with a temporary link When sending out a link to the user where they can change their password, there is a recommended practice to encrypt the information so that it is not sent as clear texts. Here is an example of how it could look in C#. details summary Here is an example of how it could look in C#. ```csharp public class PasswordResetHelper { /// /// Create the clickable link to send to the users registered email /// The current timestamp is part of the token /// public string CreateLinkToTheMail(string loginName) { var token = $"{account.LoginName}|{DateTime.Now}"; token = RijndaelEncryption.EncryptToUrl(token); return $"{PathHelper.FullBaseUrl()}login;token={token}"; } /// /// Resolve the login name from the token in the link. /// /// LoginName 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 - [Customer in Norce Commerce Services](/api-reference/services/customerservice/openapi)