[[service]] 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 [[service]] 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 [[service]] applications. Email- and phone-based authentication methods may be freely enabled or disabled in the "authentication" tab of the [[console]].
[[service]] 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 configure SMS sending for phone authentication, follow inscrutions at section Setting up SMS sending.
Creation of internally managed identities
Each created email- or phone-based identity also creates a [[service]] user account associated to this identity. In future versions, it will be possible to bind other identities (from any authentication method) to an existing account. Typically, the same end user will be allowed to authenticate either with one or more email- or phone-based credentials or with a google or facebook account. Consequently, applications should manage their users always using their account uid, but never using their identity id (i.e. their email address in case of email-based authentication method or their phone number in case of phone-based authentication method).
Email-based identities
In this case, the identifier of the identity to create must be a valid email address. After creation, the specified email address is sent a link with a token to validate it (see next section). To create a new email-based identity (and therefore a new [[service]] user account) for a given application, use the following snippet [[snippet]]:
// Create a connection to the back-end
var ref = new Webcom("<your-app>");
// Create a new email-based identity
ref.addAccount("password", {
id: "macadamia@webcom.com",
password: "nutbrittle"
}).then(function(identity) {
console.log("User identity created and bound to the new account uid:", identity.uid);
})
.catch(function(error) {
console.log("User identity not created:", error);
});
Webcom ref = new Webcom("[[baseUrl]]/base/<your-app>");
ref.addAccount("password", new AuthDetails("macadamia@webcom.com").setPassword("nutbrittle"), new OnAuth() {
@Override
public void onComplete(@Nullable AuthResponse response) {
// User identity created and bound to a new account uid
String uid = response.getUid();
}
@Override
public void onError(WebcomError error) {
// User identity not created
}
});
The identity
parameter received by the given callback is a JSON structure representing the created identity, with the following fields:
Field Type Description provider
String The authentication method associated to the newly created identity, here: "password". providerUid
String The identity ID, here the email address used to log in. uid
String The newly created user account ID, to which the identity is bound.
It is unique across all authentication methods.createdAt
Number The date (expressed in seconds since the Unix epoch) of creation of the identity. providerProfile
Object (optional) The profile data associated to the identity, which can be specified using the profile
attribute within the identity details object passed as second argument of theaddAccount()
function.
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 just created (email-based)
identity.
Phone-based identities
In this case, the identifier of the identity to create must be a valid MSISDN without the "+" prefix, which is capable of receiving SMS. After creation, the specified phone number is sent a SMS with a one time temporary code that can validate it (see next section). To create a new phone-based identity (and therefore a new [[service]] user account) for a given application, use the following snippet [[snippet]]:
// Create a connection to the back-end
var ref = new Webcom("<your-app>");
// Create a new phone-based identity
ref.addAccount("phone", {
id: "33612345678"
}).then(function(identity) {
console.log("User identity created and bound to the new account uid:", identity.uid);
})
.catch(function(error) {
console.log("User identity not created:", error);
});
Webcom ref = new Webcom("[[baseUrl]]/base/<your-app>");
ref.addAccount("phone", new AuthDetails("33612345678"), new OnAuth() {
@Override
public void onComplete(@Nullable AuthResponse response) {
// User identity created and bound to a new account uid
String uid = response.getUid();
}
@Override
public void onError(WebcomError error) {
// User identity not created
}
});
The identity
parameter received by the given callback is a JSON structure representing the created identity, with the following fields:
Field Type Description provider
String The authentication method associated to the newly created identity, here: "phone". providerUid
String The identity ID, here the MSISDN (without the "+" prefix) used to log in. uid
String The newly created user account ID, to which the identity is bound.
It is unique across all authentication methods.createdAt
Number The date (expressed in seconds since the Unix epoch) of creation of the identity. providerProfile
Object (optional) The profile data associated to the identity, which can be specified using the profile
attribute within the identity details object passed as second argument of theaddAccount()
function.
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 just created (phone-based)
identity.
Verification of internally managed identities
Once created, an internally managed identity is set in the unverified state. It cannot be used to authenticate any user until it is verified. To verifiy it, one needs the identity identifier (email address or phone number), the identity descriptor returned by the previous identity creation method, and the verification token or code received by the user at her/his email address or phone number.
If the verification method succeeds, then the user is automatically authenticated with the verified identity, there is no need to authenticate explicitly.
Email-based identities
To verify an email-based identity, simply use the following snippet [[snippet]]. This code may typically be on the verification page that the verification email sent to the user links to:
// Create a connection to the back-end
var ref = new Webcom("<your-app>");
// Create a new phone-based identity
ref.verifyIdentity("password", "macadamia@webcom.com", {
token: "...the.verification.token.received.by.the.user.at.her/his.email.address..."
}).then(function(identity) {
console.log("User identity verified, now authenticated with uid:", identity.uid);
})
.catch(function(error) {
console.log("User identity verification failed:", error);
});
Webcom ref = new Webcom("[[baseUrl]]/base/<your-app>");
ref.verifyIdentity("password", "macadamia@webcom.com",
new VerificationData("...the.verification.token.received.by.the.user.at.her/his.email.address..."),
new OnAuth() {
@Override
public void onComplete(@Nullable AuthResponse response) {
// User identity verified and user authenticated
String uid = response.getUid();
}
@Override
public void onError(WebcomError error) {
// User identity not verified
}
});
Alternatively, the identity may be verified using the following HTTP REST request:
curl -X PUT "[[baseUrl]]/auth/v2/<your-app>/password/identities/<id>/verify"
-d '{"token":"<verification-token>"}' -H 'Content-type: application/json'
where:
<your-app>
must be replaced with your application identifier. If your verification page is not application-specific, it can be passed to the verification page as a query-string using the%app%
macro within the message template edited on the [[console]].<id>
must be replaced with the email address of the identity to verify. It can be passed to the verification page as a query-string using the%id%
macro within the message template edited on the [[console]].<verification-token>
must be replaced with the token received by the user at her/his email address. It can be passed to the verification page as a query-string using the%token%
macro within the message template edited on the [[console]].
In case of success, the HTTP request returns a [[service]] token that authenticates the user with the verified identity.
If the final user doesn't receive the verification token in her/his mailbox for some reason (although it is seldom it may occur as the email dispatching infrastructures are not guaranteed 100% reliable), you can ask the [[service]] back-end to send it again so that the user has a chance to finalize her/his email address verification:
// Create a connection to the back-end
var ref = new Webcom("<your-app>");
// Send a message with a verification token
ref.sendVerificationCode("password", "macadamia@webcom.com") // the email for which verification token must be resent
.then(() => console.log("The verification token was sent successfully"))
.catch(error => console.log("The verification token was not sent:", error));
// Create a connection to the back-end
var ref = new Webcom("<your-app>");
// Send a message with a verification token
ref.sendVerificationCode("password", "macadamia@webcom.com") // the email for which verification token must be resent
.then(() => console.log("The verification token was sent successfully"))
.catch(error => console.log("The verification token was not sent:", error));
Webcom ref = new Webcom("[[baseUrl]]/base/<your-app>");
ref.sendVerificationCode("password", "macadamia@webcom.com", new OnAuth(){
@Override
public void onComplete(@Nullable AuthResponse response) {
// The verification token was sent successfully
}
@Override
public void onError(WebcomError error) {
//The verification token was not sent
}
});
Phone-based identities
To verify a phone-based identity, simply use the following snippet [[snippet]]. This code may typically follow the one at the previous section to create the identity:
// Create a connection to the back-end
var ref = new Webcom("<your-app>");
// Create a new phone-based identity
ref.verifyIdentity("phone", "33612345678", {
auth: {/*the identity object resulting from the previous call to the addAccount(...) method*/},
password: "<the.one.time.password.received.by.the.user.on.her/his.phone"
}).then(function(identity) {
console.log("User identity verified, now authenticated with uid:", identity.uid);
}).catch(function(error) {
console.log("User identity verification failed:", error);
});
Webcom ref = new Webcom("[[baseUrl]]/base/<your-app>");
ref.verifyIdentity("phone", "33612345678",
new VerificationData(/*AuthResponse object resulting from the previous call to the addAccount(...) method*/,
"...the.one.time.password.received.by.the.user.on.her/his.phone..."),
new OnAuth() {
@Override
public void onComplete(@Nullable AuthResponse response) {
// User identity verified and user authenticated
String uid = response.getUid();
}
@Override
public void onError(WebcomError error) {
// User identity not verified
}
});
If the final user doesn't receive the SMS containing the verification code, as this code is valid for a very short time, then the whole process of creating the user and verifying her/his phone-based identity must be replayed. There is no mean to send again the same verification code.
Login with internally managed identities
Email-based identities
Once confirmed, an email-based identity can be used to log in, using the following snippet [[snippet]]:
// Create a connection to the back-end
var ref = new Webcom("<your-app>");
// Log in
ref.authWithPassword({
email : "macadamia@webcom.com",
password : "my-password"},
function(error, auth) {
if (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 [[console]].");
break;
default:
console.log("An unexpected error occurs, please retry and contact your administrator.", error);
}
} else {
console.log("Authentication succeeded", auth);
}
}
);
Webcom ref = new Webcom("[[baseUrl]]/base/<your-app>");
ref.authWithPassword("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
}
});
The auth
parameter received by the authentication callback function is a JSON structure representing the identity used to log in.
In addition to the generic fields, it includes the following ones:
Field Type Description provider
String Equals "password". providerUid
String The email address of the logged in user. providerProfile
Object (optional) The profile of the logged in user, when specified at creation with the addAccount()
method.
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 identity used to log in.
Phone-based identities
Login with a phone identity is a 2-steps process:
- Send a SMS to the user with the phone number containing a one time password (OTP) dedicated to the login operation,
- Log 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 [[snippet]]:
// Create a connection to the back-end
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.authWithPhone({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}`));
// Create a connection to the back-end
Webcom ref = new Webcom("[[baseUrl]]/base/<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
}
});
The auth
parameter received by the authentication callback function is a JSON structure representing the identity used to log in.
In addition to the generic fields, it includes the following ones:
Field Type Description provider
String Equals "phone". providerUid
String The MSISDN of the logged in user (without the "+" prefix). providerProfile
Object (optional) The profile of the logged in user, when specified at creation with the addAccount()
method.
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.
Update of internally managed identities
Updating password
There are 2 cases to update the password of an email-based identity: either you know the currently associated
password, or you don't know (or have forgotten) it.
In the first case, simply use the changePassword()
method [[snippet]]:
// Create a connection to the back-end
var ref = new Webcom("<your-app>");
// Update the password
ref.changePassword("chocolate@webcom.com", // email
"pralinesandcaramel", // current password
"midnightcookies", // new password
function(error) {
if (error === null) {
console.log("Password changed successfully");
} else {
console.log("Error changing password:", error);
}
});
// Create a connection to the back-end
var ref = new Webcom("<your-app>");
// Update the password
ref.changePassword("chocolate@webcom.com", // email
"pralinesandcaramel", // current password
"midnightcookies" // new password
).then(function() {
console.log("Password changed successfully");
}).catch(function(error) {
console.log("Error changing password:", error);
});
Webcom ref = new Webcom("[[baseUrl]]/base/<your-app>");
ref.changePassword("chocolate@webcom.com", "pralinesandcaramel", "midnightcookies", new OnAuth(){
@Override
public void onComplete(@Nullable AuthResponse response) {
// Password changed successfully
}
@Override
public void onError(WebcomError error) {
// Error changing password
}
});
In the second case, use the sendPasswordResetEmail()
method [[snippet]]:
// Create a connection to the back-end
var ref = new Webcom("<your-app>");
// Send a message to reset the password
ref.sendPasswordResetCode("password", "macadamia@webcom.com") // the email for which the password must be reset
.then(() => console.log("The Reset password email was sent successfully"))
.catch(error => console.log("The Reset password email was sent successfully"));
// Create a connection to the back-end
var ref = new Webcom("<your-app>");
// Send a message to reset the password
ref.sendPasswordResetCode("password", "macadamia@webcom.com") // the email for which the password must be reset
.then(() => console.log("The Reset password email was sent successfully"))
.catch(error => console.log("The Reset password email was not sent:", error));
Webcom ref = new Webcom("[[baseUrl]]/base/<your-app>");
ref.sendPasswordResetCode("password", "chocolate@webcom.com", new OnAuth(){
@Override
public void onComplete(@Nullable AuthResponse response) {
// The Reset password email was sent successfully
}
@Override
public void onError(WebcomError error) {
//The Reset password email was not sent
}
});
The [[service]] back-end then emails a message to the specified user, with a link to safely change her/his password without need of the current password. The default message links to a generic page served by the [[service]] back-end.
In order to customize the user experience for resetting an identity password, you can edit the message template in the "authentication" tab of the [[console]]. You can then include a link to a customized reset page from your application. In turn, this page must end in requesting the following HTTP REST [[service]] API:
curl -X PUT "[[baseUrl]]/auth/v2/<your-app>/password/update"
-H "Authorization: Bearer <reset-token>"
-H "Content-Type: application/x-www-form-urlencoded"
-d "newPassword=<new-password>"
Where:
<your-app>
must be replaced with your application identifier. If your password reset page is not application-specific, it can be passed to the password reset page as a query-string using the%app%
macro within the message template edited on the [[console]].<reset-token>
must be replaced with the token generated by the [[service]] back-end when it sent the password reset message to the user. It can be passed to the reset page as a query-string using the%token%
macro within the message template edited on the [[console]].<new-password>
must be replaced with the new password to associate to the user's email. It typically comes from a form displayed by the password reset page.
Note: this parameter is part of an URL-encoded form data, therefore it has to be percent-encoded with UTF-8 encoding.
Updating profile
As mentioned above, when creating an email- or phone-based identity, a profile may be associated to
it, which is specified as a JSON object. In order to update this profile, you can use the updateIdentityProfile
method. It requires that you are already authenticated with an email- or phone-based identity, it will then update the
profile associated to this currently authenticated identity.
// Authenticate with an email-based identity...
var ref = new Webcom("<your-app>");
ref.authWithPassword({email: "macadamia@webcom.com", password: "my-password"}, function(error) {
if (!error) {
// ...and then update its profile
ref.updateIdentityProfile({age: 42, zipcode: 22300})
.then(() => console.log("The profile has been successfully updated"))
.catch(error => console.log("The update failed:", error));
}
})
// Authenticate with an email-based identity...
let ref = new Webcom("<your-app>");
ref.authWithPassword({email: "macadamia@webcom.com", password: "my-password"})
.then(() => {
// ...and then update its profile
ref.updateIdentityProfile({age: 42, zipcode: 22300})
.then(() => console.log("The profile has been successfully updated"));
})
.catch(error => console.log("The update failed:", error));
// Authenticate with an email-based identity...
Webcom ref = new Webcom("[[baseUrl]]/base/<your-app>");
ref.authWithPassword("macadamia@webcom.com", "my-password", new OnAuth() {
@Override
public void onComplete(@Nullable AuthResponse response) {
// ...and then update its profile
ref.updateIdentityProfile("age", 42, new OnAuth() {
@Override
public void onComplete(@Nullable AuthResponse response) {
// profile updated!
}
@Override
public void onError(WebcomError error) {
...
}
});
}
@Override
public void onError(WebcomError error) {
...
}
});
If no user is currently authenticated or if the currently authenticated user is not identified with an email- or phone-based identity, then the method will end in rejecting the returned promise with an error.