# Implement registration, login and one-time-access link

Source: https://dev.arcxp.com/subscriptions/identity/build/implement-registration-login-one-time-access/

> **Note:**
> 
> Registration, Login and One-Time-Access links flows are available via Themes blocks. See [Arc XP Identity Themes Blocks configuration & Customization Deep Dive](https://dev.arcxp.com/subscriptions/identity/configure/arc-xp-identity-themes-blocks-configuration-customization-deep-dive/) for additional details.
> 
> If you want to built your own implementation, we will walk through this document using our SDK methods, but if you need to call the APIs directly, please check [How-to Connect and log in with Arc XP Identity SDKs and APIs on the web](https://dev.arcxp.com/subscriptions/identity/build/connect-and-login-with-arc-xp-identity-sdks-and-apis/) to see the API that our SDK methods are wrapping.

## Prerequisites

- Initialize the [Arc XP Identity SDK package](https://dev.arcxp.com/subscriptions/identity/build/connect-and-login-with-arc-xp-identity-sdks-and-apis/#using-the-subscriptions-app-from-a-public-domain-through-the-sdk)
- **Obtain the configuration for the tenant.**A successful sign-up depends on whether the [password meets the minimum requirements](https://dev.arcxp.com/subscriptions/identity/configure/password-settings-secure-your-users-accounts-with-password-requirements/#password-management) defined in the subscription settings. Additionally, registration, login, and one-time access flows may be [protected with reCAPTCHA](https://dev.arcxp.com/subscriptions/identity/configure/secure-your-site-against-attacks-cors-domains-blocked-email-domains-and-recaptcha/#recaptcha). Therefore, it is necessary to retrieve the configuration to understand the setup for the tenant (organization and site). Thus, you can add additional validation to the password fields, and show/hide the reCaptcha component based on the settings.

```js
import Identity from '@arc-publishing/sdk-identity';
...
const [siteConfigs, setSiteConfigs] = useState();
useEffect(()=>{
  const getSiteConfigs = async () => {
      try {
        await Identity.getConfig().then(config => {
          setSiteConfigs(config);
        });
      } catch (e) {
        alert(e.message);
      }
    };
    getSiteConfigs();
},[]);
```

## Registration

Arc XP Identity provides full ability for users to create an account by providing basic user information: username, email address, and password.

A user account can be created in one of the following ways:

- **Email and Password:** User provides basic credentials: email or username and credentials (password)
- **Social authentication providers:** Facebook, Google, Apple and OIDC login methods are available. For more details on that setup, and implementation, please check [Configure third-party authentication providers: Facebook, Google, Apple, and OIDC](https://dev.arcxp.com/subscriptions/identity/configure/third-party-authentication-providers-facebook-google-apple/) and [Implement Social Sign In](https://dev.arcxp.com/subscriptions/identity/build//how-to-implement-social-sign-in/).

This document will guide you through regular login (email+password).

Before setting up your Identity forms, you must determine how you want to configure your usernames. The available options are global.

- **UsernameIsEmail** set to **TRUE** configures Identity so _Profile.identities.username_ is updated when _Profile.Email_ changes. These two profile values are kept in sync and users are not able to have a separate username from their email.
- **UsernameIsEmail** set to **FALSE** allows users to set a _username_ for their login. The _username_ can be their _email_ or a _username_ of their choice.

User accounts are global and a pool across all sites. Check with the Subscriptions team to know what is the setting your org has.

1. **Create the registration form**  
The Signup form should have at least two input fields for email and password, and a button to send the form. Below is an example of a Signup form.

**Recomendations**

  - Make sure the user meets the minumum password requirements before send the form. You will need to check _pwMinLength_, _pwSpecialCharacters_, _pwLowercase_, _pwUppercase_, _pwNumbers_ values returned from `Identity.getConfig()`
  - Enforce the client to enter the password two times.
  - Make sure you are showing handling/displaying errors in case sometime went wrong during the Signup request.  
![Registration form](https://dev.arcxp.com/images/subscriptions/identity/build/implement-registration-login-one-time-access/registration-form.png)  
This form can request additional user information such as firstName, lastName, second last name, date of birth, phone number, additional attributes.
2. **Display or hide reCAPTCHA** based on the tenant settings  
Your site can be [protected by reCAPCTHA](https://dev.arcxp.com/subscriptions/identity/configure/secure-your-site-against-attacks-cors-domains-blocked-email-domains-and-recaptcha/#recaptcha). You will need to show or hide the reCAPTCHA component (v2 o v3) based on the settings you have defined on the Admin for your site.  
_recaptchaScore_, _recaptchaSiteKey_, and _signupRecaptcha_ returned from `Identity.getConfig()` are used to implement reCAPCTHA in your site.

  - If _signupRecaptcha_ is true, that means reCAPTCHA is enabled for Registration.
  - If _signinRecaptcha_ is true, that means reCAPTCHA is enabled for Login.
  - If _magicLinkRecaptcha_ is true, that means reCAPTCHA is enabled for One-time-access link.
  - If _recaptchaScore_ is -1, reCAPTCHA V2 is enabled, else if _recaptchaScore_ has a value between 0 and 1, reCAPTCHA V3 is enabled.  
Hook returning the current settings.  
```js
    import { useState, useEffect } from 'react';
    import Identity from "@arc-publishing/sdk-identity";
    const useRecaptcha = () => {
        const [recaptchaVersion, setRecaptchaVersion] = useState(null);
        const [recaptchaSiteKey, setRecaptchaSiteKey] = useState(null);
        const [reCaptchaLogin, setRecaptchaLogin] = useState(false);
        const [reCaptchaSignUp, setRecaptchaSignUp] = useState(false);
        const [reCaptchaMagicLink, setRecaptchaMagicLink] = useState(false);
        useEffect(() => {
            Identity.getConfig().then(config => {
                if (config?.recaptchaScore === '-1') {
                    setRecaptchaVersion('V2');
                }
                if (0 <= parseFloat(config?.recaptchaScore) && parseFloat(config?.recaptchaScore) <= 1) {
                    setRecaptchaVersion('V3');
                }
                setRecaptchaSiteKey(config?.recaptchaSiteKey);
                setRecaptchaLogin(config?.signinRecaptcha);
                setRecaptchaSignUp(config?.signupRecaptcha);
                setRecaptchaMagicLink(config?.magicLinkRecaptcha);
            });
        }, []);
        return {
            recaptchaVersion,
            recaptchaSiteKey,
            reCaptchaLogin,
            reCaptchaSignUp,
            reCaptchaMagicLink
        };
    };
    export default useRecaptcha;
```
Display reCAPTCHA V2 or V3 based on the settings returned by the useRecaptcha hook.  
```js
    import React, { useState, useEffect, useCallback } from 'react';
    import { ReCaptcha } from 'react-recaptcha-google';
    import { useGoogleReCaptcha } from 'react-google-recaptcha-v3';
    import useRecaptcha from '../hooks/useRecaptcha';
    ...
    export const Register = () => {
        ...
        const [email, setEmail] = useState('');
        const [captchaToken, setCaptchaToken] = useState();
        const { recaptchaVersion, reCaptchaSignUp, recaptchaSiteKey } = useRecaptcha();
        let captchaRef;
        const { executeRecaptcha } = useGoogleReCaptcha();
        const handleReCaptcha3Verify = useCallback(async () => {
            if (!executeRecaptcha) {
                console.log('reCAPTCHA execution is not yet available.');
            return;
            }
            const token = await executeRecaptcha();
            setCaptchaToken(token);
        }, [executeRecaptcha]);
        useEffect(() => {
            if (recaptchaVersion === 'V3' && reCaptchaSignUp) {
                handleReCaptcha3Verify();
            }
        }, [recaptchaVersion, reCaptchaSignUp, executeRecaptcha]);
        const onLoadRecaptcha = () => {
            if (captchaRef) {
                captchaRef.reset();
            }
        };
        if (recaptchaVersion === 'V2' && reCaptchaSignUp) {
            onLoadRecaptcha();
        }
        const verifyCallback = token => {
            setCaptchaToken(token);
        };
        return (
            <main>
                <section>
                    <h1>Sign up!</h1>
                    <form
                        onSubmit={e => {
                            e.preventDefault();
                            return Identity.signUp(
                                {
                                    userName: email,
                                    credentials: password
                                },
                                {
                                    email
                                },
                                undefined,
                                true,
                                captchaToken
                            )
                            .then(() => {
                                //Go to the profile page or the page where you want the user to land after a successful Sign up.
                            })
                            .catch(e){
                                // Grab the error to provide on the page something went wrong
                            };
                        }}
                    >
                        <input
                            placeholder="Email"
                            type="email"
                            id="email"
                            className="input"
                            value={email}
                            onChange={e => setEmail(e.target.value)}
                        />
                        ...
                        {reCaptchaSignUp && recaptchaVersion === 'V2' && (
                            <ReCaptcha
                                ref={el => {
                                    captchaRef = el;
                                }}
                                size="normal"
                                render="explicit"
                                sitekey={recaptchaSiteKey}
                                onloadCallback={onLoadRecaptcha}
                                verifyCallback={verifyCallback}
                            />
                        )}
                        <button type="submit">
                            Sign Up
                        </button>
                    </form>
                </section>
            </main>
        );
    }
```
    ); }">
3. **Call Identity.SignUp() method**  
As part of the code provided above you can see Identity.SignUp() is called, and the values on the form (including the reCAPTCHA token) are sent as part of the request.

## Login

A user can ask for Login in two different ways:

- **Email and Password:** User provides basic credentials: email or username and credentials (password)
- **Social authentication providers:** Facebook, Google, Apple and OIDC login methods are available. For more details on that setup, and implementation, please check [Configure third-party authentication providers: Facebook, Google, Apple, and OIDC](https://dev.arcxp.com/subscriptions/identity/configure/third-party-authentication-providers-facebook-google-apple/) and [Implement Social Sign In](https://dev.arcxp.com/subscriptions/identity/build/how-to-implement-social-sign-in/).
1. **Create the Login form**  
The Login form should have two input fields for email (or username) and password, and a button to send the form. Below is an example of a Login form.

**Recomendations**

  - Make sure you are showing handling/displaying errors in case sometime went wrong during the Login request.  
![Login form](https://dev.arcxp.com/images/subscriptions/identity/build/implement-registration-login-one-time-access/login-form.png)
2. Display or hide reCAPTCHA based on the tenant settings  
The logic for this page is the same as described for [Registration](https://dev.arcxp.com/subscriptions/identity/build/implement-registration-login-one-time-access/#registration). However, to determine if reCAPTCHA is enabled for login, you will need to check the _reCaptchaLogin_ value returned by the `useRecaptcha` hook.
3. **Call Identity.Login() method**  
```js
    ...
    onSubmit={e => {
        e.preventDefault();
        return Identity.login(username, password, {
          true,
          recaptchaToken: captchaToken
        })
          .then(async () => {
            //Go to the profile page or the page where you want the user to land after a successful login.
          })
          .catch(error => {
            // Grab the error to provide on the page something went wrong
          });
      }}
```

## One-time-access link

Sometimes, users can’t recall their password (or don’t have access to their password keeper) but want to log in without going through the password reset process. Passwordless authentication allows users to authenticate without the need to login with a password. With this form of authentication, users are presented with the option of logging in simply via a **one-time-access** link (previously called **magiclink**), which uses a _nonce_ (i.e. token) delivered via email. To authenticate, the user clicks the link with the embedded _nonce_ granting them a user session.

The _nonce_ can be used a single time and expires after 24 hours. Once the user is granted a session, the `refresh-token` will be valid for 24 hours.

![Login form](https://dev.arcxp.com/images/subscriptions/identity/build/implement-registration-login-one-time-access/one-time-access-link-flow.png)

1. **Create the One-time-access link form**  
The one-time-access link form should have an input field for email, and a button to send the form. Below is an example of a one-time-access link form.  
![Registration form](https://dev.arcxp.com/images/subscriptions/identity/build/implement-registration-login-one-time-access/one-time-access-link-form.png)
2. Display or hide reCAPTCHA based on the tenant settings  
The logic for this page is the same as described for [Registration](https://dev.arcxp.com/subscriptions/identity/build/implement-registration-login-one-time-access/#registration). However, to determine if reCAPTCHA is enabled for requesting one-time-access link, you will need to check the _magicLinkRecaptcha_ value returned by the `useRecaptcha` hook.
3. **Call Identity.requestOTALink() method**  
```js
    onSubmit={e => {
        e.preventDefault();
        return Identity.requestOTALink(email, captchaToken)
          .then(() => {
            // Provide a message indicating to the user a email was sent to their email
          })
          .catch(error => {
            // Grab the error to provide on the page something went wrong
          });
      }}
```
Once the user clicks on **Send One-Time-Access link**, and if the request is successful, you will need to notify the user that an email containing a link has been sent to their email address.  
Only if the email exists in Arc XP Identity, a Web Socket event named [\_MAGIC\_LINK\_SEND\_](https://dev.arcxp.com/subscriptions/identity/learn/list-of-identity-events/#one-time-access-link-request) is created. The client is on charge to send a link containing the _nonce_ created as part of the web socket event. See [How-to listen Web Socket events and Implement IFX email service provider](https://dev.arcxp.com/subscriptions/identity/build/ifx-email-servic-provider-integration-and-websocket-events/) for more details
4. **Redeem the nonce**  
```js
    try {
        await Identity.redeemOTALink(nonce);
        //Go to the profile page or the page where you want the user to land after a successful login.
    } catch (e) {
        setErr(e);
    }
```
Once the reader clicks on this link, Arc XP identity will validate the _nonce_ by calling Identity.redeemOTALink() and, if successful, log the user in to the site.
