Tutorial: Login with email or phone

Serverless AuthenticationSigning in and out Login with email or phone

Webcom is able to provide internally managed identities to authenticate users. Currently two kinds of identities are provided:

  • Email-based identities rely on the user's email address,
  • Phone-based identities rely on the user's mobile phone number (or at least a phone number which can receive SMS).

Credentials to authenticate these identities are either securely stored and encrypted in the Webcom back end (typically when users are prompted to enter a permanent password) or securely and randomly generated on demand (typically when the users are sent a one time password).

By default, only the email-based authentication method is enabled on new Webcom applications. Email- and phone-based authentication methods may be freely enabled or disabled in the "authentication" tab of the Webcom developer console.

Webcom SDK exposes functions to create, authenticate and update internally managed (email- and phone-based) identities, letting the application developer have full control over the user interface.

In order to ensure that the SMS will be successfully sent to the users when using phone authentication, you must subscribe to a (generally charged) SMS sending service and properly set it up in the "phone" cartridge of the "authentication" tab in the Webcom developer console. You can find the complete instructions at the Setting up SMS sending section.

Login with internally managed identities

Email-based identities

Once confirmed, an email-based identity can be used to sign in, using the following snippet (replace “<your-app>” with your actual application identifier):

var ref = new Webcom("<your-app>");
ref.authInternally("password", {
        id: "macadamia@webcom.com",
        password: "my-password"})
   .then(auth => console.log("Authentication succeeded", auth))
   .catch(error => {
     switch (error.code) {
       case "INVALID_CREDENTIALS":
         console.log("The email or password is incorrect.");
         break;
       case "PROVIDER_DISABLED":
         console.log("The email-based authentication method is disabled in the application. It must be enabled in the Webcom developer console.");
         break;
       default:
         console.log("An unexpected error occurs, please retry and contact your administrator.", error);
     }
   }
);

The auth parameter returned in the promise is a JSON object representing the signed in identity, which directly feeds the current authentication state. The following properties are specialized this way:

Property Type Description
provider string Equals "password".
providerUid string The email address of the signed in user.
providerProfile object (optional) The profile of the signed in user, when specified at signup with the addIdentity() method.
Webcom ref = new Webcom(new WebcomApp("<your-app>"));
ref.authInternally("password", "macadamia@webcom.com", "my-password", new OnAuth(){
  @Override
  public void onComplete(@Nullable AuthResponse authResponse) {
    // User account authenticated
    String token = authResponse.getToken();
  }
  @Override
  public void onError(WebcomError error) {
    // User account not authenticated
  }
});

In case of error, the onError method is called with an object describing the root cause of the error. Otherwise, the onComplete method is called with an authResponse representing the signed in identity, which directly feeds the current authentication state.

let authenticationService = Webcom.defaultApplication.authenticationService
let internalMethod = AuthenticationMethodInternal(eMail: "macadamia@webcom.com")
authenticationService.initializeAuthentication(with: internalMethod)
internalMethod.setStaticPassword("my-password")
authenticationService.continueAuthentication { result in
    switch result {
    case let .success(details):
        print("Authenticated with token:", details.authenticationToken)
    case let .failure(error):
        print("Error:", error)
    }
}

Phone-based identities

Signing in with a phone-based identity is a 2-steps process:

  1. Send to the user a SMS containing a one time password (OTP) dedicated to the sign in operation,
  2. Sign the user in by providing, in addition to the user's phone number, the identifier of the OTP previously sent (called challenge) and the OTP itself received by the user.
sequenceDiagram participant U as User participant A as Application participant B as Webcom A->>+B: Request to send a one time password B->>U: Send *otp* by SMS B->>-A: *challenge* U->>A: Provide received *otp* A->>B: Request to authenticate with *msisdn*, *challenge*, *otp* B->>A: *authentication state*

To do so, use the following snippet (replace “<your-app>” with your actual application identifier):

let ref = new Webcom("<your-app>");
let phoneId = "33612345678";
// Send the OTP
ref.sendOtp("phone", phoneId)
    .then(challenge => {
        askTheUserForTheReceivedOtp() // function expected to prompt the user with an input box to enter the OTP
            .then(otp => {
                // Actually log in
                ref.authInternally("phone", {id: phoneId, challenge: challenge, password: otp})
                    .then(auth => console.log(`Logged in with uid: ${auth.uid}`))
                    .catch(error => console.log(`Login failed: ${error}`));
            })
            .catch(() => console.log('The user gave up the login operation...'));
    })
    .catch(error => console.log(`Failed to send OTP: ${error}`));

The auth parameter returned by the promise of the authInternally() method is a JSON object representing the signed in identity, which directly feeds the current authentication state. The following properties are specialized this way:

Property Type Description
provider string Equals "phone".
providerUid string The MSISDN of the signed in user (without the "+" prefix).
providerProfile object (optional) The profile of the signed in user, when specified at signup with the addIdentity() method.
Webcom ref = new Webcom(new WebcomApp("<your-app>"));
String phoneId = "33612345678";
// Send the OTP
ref.sendOtp("phone", phoneId, new OnValue() {
  @Override
  public void onValue(JSONValue challenge) {
    String otp = askTheUserForTheReceivedOtp(); // method expected to prompt the user with an input box to enter the OTP
    ref.authWithPhone(phoneId, challenge.stringify(), otp, new OnAuth() {
      @Override
      public void onComplete(@Nullable AuthResponse authResponse) {
        // User account authenticated
        String token = authResponse.getToken();
      }
      @Override
      public void onError(WebcomError error) {
        // User account not authenticated
      }
    });
  }
  @Override
  public void onError(WebcomError error) {
    // Failed to send OTP
  }
});

In case of error (when sending the OTP or when authenticating), the onError method is called with an object describing the root cause of the error.

Otherwise, after successful sending of the OTP, the onValue method is called with the identifier of the sent OTP (or challenge) passed as a JSONValue. Then, after successful authentication, the onComplete method is called with an authResponse representing the identity used to log in.

let authenticationService = Webcom.defaultApplication.authenticationService
let internalMethod = AuthenticationMethodInternal(msisdn: "33612345678")
authenticationService.initializeAuthentication(with: internalMethod)
internalMethod.requestOneTimePassword { result in
    switch result {
    case .success:
        let code = "..." // In fact, you would probably use another view controller to ask the code to the user.
        internalMethod.setOneTimePassword(code)
        authenticationService.continueAuthentication { result in
            switch result {
            case let .success(details):
                print("Authenticated with token:", details.authenticationToken)
            case let .failure(error):
                print("Error:", error)
            }
        }
    case let .failure(error):
        print("Failed to send OTP:", error)
    }
}