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.
Sign in 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):
// const app = Webcom.App("<your-app>"); // UNCOMMENT if you haven't yet an instance of your app!
// Get an instance of the authentication service
const auth = app.authentication;
// Sign in with email
auth.signInWithCredentials("password", {
id: "macadamia@webcom.com",
password: "my-password"})
.then(authDetails => console.log("Authentication succeeded", authDetails))
.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 authDetails
parameter returned by 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. |
val myApp = WebcomApplication.default // the app defined by the 'webcom.properties' asset file
val authenticator = myApp.authenticationService
authenticator
.getPersonalPasswordMethod(Provider.Email, "macadamia@webcom.com")
.authenticate("my-password") {
when (it) {
is WebcomResult.Success -> print("logged in with the token: ${it.result.authenticationToken}")
is WebcomResult.Failure -> print("error: ${it.error.errorCode}")
}
}
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:
- Send to the user an SMS containing a one time password (OTP) dedicated to the sign in operation,
- 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.
To do so, use the following snippet (replace “<your-app>” with your actual application identifier):
// const app = Webcom.App("<your-app>"); // UNCOMMENT if you haven't yet an instance of your app!
// Get an instance of the authentication service
const auth = app.authentication;
const phoneId = "33612345678";
// Send the OTP
auth.sendOtp("phone", phoneId)
.then(challenge => {
askTheUserForTheReceivedOtp() // function expected to prompt the user with an input box to enter the OTP
.then(otp => {
// Actually sign in
auth.signInWithCredentials("phone", {id: phoneId, challenge: challenge, password: otp})
.then(authDetails => console.log(`Logged in with uid: ${authDetails.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 authDetails
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. |
val myApp = WebcomApplication.default // the app defined by the 'webcom.properties' asset file
val authenticator = myApp.authenticationService
fun askTheUserForTheReceivedOtp(callback: (String) -> Unit) {
// this method is expected to prompt the user with an input box to enter the received OTP
// the entered OTP is the passed back to the `callback` parameter as a String
}
with(authenticator.getOneTimePasswordMethod(Provider.Phone, "33612345678")) {
sendOneTimePassword { // it: WebcomResult<Unit>
if (it is WebcomResult.Failure) print("SMS could not be sent: ${it.error.errorCode}")
else askTheUserForTheReceivedOtp { otp: String ->
authenticate(otp) { auth: WebcomResult<AuthenticationDetails> ->
when (auth) {
is WebcomResult.Success -> print("logged in with the account: ${auth.result.authenticationToken}")
is WebcomResult.Failure -> print("error: ${auth.error.errorCode}")
}
}
}
}
}
Note that the OneTimePasswordMethod
object returned by the getOneTimePasswordMethod()
manages the challenge received from the back end by its own, and
its authenticate()
method requires to be passed only the OTP received by the user.
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)
}
}