Tutorial: Authentication state

Serverless Authentication Authentication state

The Webcom Authentication Service basically maintains an authentication state that identifies the end-user currently signed in to a given Webcom application on a given device (where the Webcom client application is executed).

The Webcom SDK provides with proper APIs to:

Authentication model

graph LR AuthState --1--> AccountUid AuthState --1--> Token AuthState --1--> ExpirationDate AuthState --1--> SignedInIdentity SignedInIdentity --1--> CreationDate SignedInIdentity --0..1--> DisplayName SignedInIdentity --0..1--> ProviderProfile SignedInIdentity --1--> Provider SignedInIdentity --1--> ProviderUid AuthState --1--> Context Context --0..*--> AuthFactor AuthFactor --1--> Provider AuthFactor --1--> ProviderUid AuthFactor --1--> SignInDate classDef common fill:grey class Provider common class ProviderUid common classDef optional stroke-dasharray:5,5 class DisplayName optional class ProviderProfile optional class AuthFactor optional

The authentication state (AuthState) gathers the following attributes about the currently signed in end-user:

  • AccountUid: it is the unique identifier of the Webcom “account” associated with the end-user. This id is unique across all users of the Webcom application whatever the authentication method used to sign in. This id should be used within the application data to refer to the end-user.

  • Token: the Webcom authentication token that encodes the current authentication state. If your application uses a specific backend, this token may be passed to requests that require user privileges.

  • ExpirationDate: the date that the token is valid until.

  • SignedInIdentity: the “identity” used by the end-user to sign in. In the Webcom model, identities in turn gather the following attributes:

    • Provider: it indicates the authentication method used to sign the user in. Each identity is associated to a unique and specific authentication method. Each authentication method corresponds to a specific “identity provider”, which can be external to the Webcom platform. The complete list of available authentication methods or identity providers is given in the Signing in and out section.

    • ProviderUid: it is the identifier representing the identity used to sign in. This identifier is unique relatively to the authentication method, that is, unique across all users that are authenticated by a given identity provider. However the same identifier may refer to distinct users relatively to distinct providers. That's why this identifier is strongly discouraged to identity end-users within an application.

    • CreationDate: it indicates when the identity was first associated to the Webcom account of the user. In other words, it is the creation date of the identity from the Webcom viewpoint (and not from the identity provider one).

    • DisplayName: it optionally indicates (depending on the identity provider) a friendly display name for the signed in user.

    • ProviderProfile: it gives some optional additional information about the signed in user, which is provided by the identity provider. This piece of information is completely specific to the authentication method.

  • Context: it gives the list of other identities used by the end-user to authenticate within this authentication session. In other words, a user may authenticate with several identities. The Webcom Authentication Service actually implements multi-factor authentication using multi-identity authentication. Each authentication factor corresponds to an identity of the user. Each factor contained in the authentication “context” provides in turn the following pieces of information:

    • Provider: the identity provider associated to the authentication factor,
    • ProviderUid: the identifier of the user (relatively to the identity provider) associated to the authentication factor,
    • SignInDate: the date when the user authenticated using this factor. It is useful for example to control that a secondary factor is not too old wrt. the main one.

    Thus, when the authentication context is empty, the user is authenticated with a single factor and this “main factor” is described by the Provider and ProviderUid attributes at the first level of the authentication state. When the authentication context contains n factors (n > 0), the user is authenticated with n+1 factors. The most recent factor is the one described by the Provider and ProviderUid attributes at the first level of the authentication sate, the second-to-last one is described by the first element of the Context attribute... and the oldest factor is described by the last element of the context attribute.

The Webcom SDK for JavaScript represents the authentication state using a JSON object with the following properties and correspondence to the authentication state attributes:

JSON property Mandatory
Optional
Type Authentication state attribute
uid M string AccountUid
webcomAuthToken M string Token
expires M number ExpirationDate expressed in seconds since Unix Epoch
provider M string SignedInIdentity / Provider
providerUid M string SignedInIdentity / ProviderUid
createdAt M number SignedInIdentity / CreationDate expressed in milliseconds since Unix Epoch
displayName O string SignedInIdentity / DisplayName
providerProfile O object SignedInIdentity / ProviderProfile given as a JSON object specific to the identity provider
context M array Context
context[i].provider M string Context / Provider
context[i].providerUid M string Context / ProviderUid
context[i].signedInAt M number Context / SignInDate expressed in seconds since Unix Epoch

Only the displayName and providerProfile properties are optional. The context property is mandatory but may be an empty array when the user is signed in with a single identity.

Note that this JSON object (without the webcomAuthToken property) is also embedded within the Webcom authentication token and is therefore passed to security rules.
Consequently, security rules can accommodate the authentication method or the available additional authentication factors used to sign in, as shown in this complete example.

The Webcom SDK for Android represents the authentication state using the OnAuth.Identity class with the following getters and correspondence to the authentication state attributes:

Identity getter Type Authentication state attribute
getUid() String AccountUid
getWebcomAuthToken() String Token
getExpires() Date ExpirationDate
getProvider() String SignedInIdentity / Provider
getProviderUid() String SignedInIdentity / ProviderUid
getCreatedAt() Date SignedInIdentity / CreationDate
getDisplayName() String SignedInIdentity / DisplayName may be null
getJSONProviderProfile() JSONValue SignedInIdentity / ProviderProfile may be null

The Webcom SDK for iOS represents the authentication state using the AuthenticationDetails struct with the following properties and correspondence to the authentication state attributes:

AuthenticationDetails property Type Authentication state attribute
uid String AccountUid
authenticationToken String Token
expirationDate Date ExpirationDate
provider AuthenticationProvider SignedInIdentity / Provider
providerUID String SignedInIdentity / ProviderUid
creationDate Date SignedInIdentity / CreationDate
displayName String? SignedInIdentity / DisplayName
providerProfile [String: Any] SignedInIdentity / ProviderProfile
previousFactors [AuthenticationFactor] Context

When a user is successfully authenticated, the completion callback of the authenticate() method is called with the .success case having an AuthenticationDetails associated value.

let method = /* ... */ // any authentication method
WebcomApplication.default.authenticationService.authenticate(with: method) { result
    switch result {
    case let .failure(error):
        print("authentication failed:", error)
    case let .success(details):
        print("authenticated with:", details.provider.prettyName, "as:", details.uid)
    }
}

Authentication callbacks

The main way to access the current authentication state maintained by the Webcom Authentication Service is to register authentication callbacks. These functions are called each time the authentication state changes and are passed the authentication state.

If an authentication operation is performed but doesn't change the current authentication state, the callbacks are not called. If an authentication operation fails, then the current authentication state is lost (consequently, the user must sign in again to perform further operations requiring an authorization).

Authentication callbacks in JavaScript are passed two parameters:

  • error: it is not null if the authentication operation that triggers the callback has failed. In this case, it is a JSON object whith 2 mandatory properties: code (the error code, see the Error messages) and message (a non-localized human-readable message).
  • authState: it must be considered only if the error parameter is null. If so, it is either null if no user is currently signed in, or the JSON object representing the authenticated user if a user is currently signed in.

Authentication callback functions may be registered or unregistered using the registerAuthCallback() and unregisterAuthCallback() methods on instances of the Webcom class. All Webcom instances on the same Webcom application share their authentication callbacks (and of course, instances on different applications have separate pools of authentication callbacks). The following snippet shows a complete example (replace “<your-app>” with your actual application identifier):

// Create a reference to a Webcom application
var ref = new Webcom("<your-app>");
// Define an authentication callback
var authCb = 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/password 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);
    }
  } else {
    console.log("Authentication succeeded", auth);
  }
};
// Register it
ref.registerAuthCallback(authCb);
// { ...
// Within this fragment, 'authCb' is called each time the authentication state changes
// ... }
// Unregister it
ref.unregisterAuthCallback(authCb);

Authentication callbacks in Android must implement the OnAuth interface, which provides two methods:

  • onComplete(): it is called when the authentication operation that triggers the callback has succeeded. If the operation was a sign in operation, this method is passed the resulting authentication state embedded into an AuthResponse. If it was a sign out operation, this method is passed null.
  • onError(): it is called when the authentication operation has failed and is passed an object describing the error.

Authentication callback functions may be registered or unregistered using the registerAuthCallback() and unregisterAuthCallback() methods on instances of the Webcom class. All Webcom instances on the same Webcom application share their authentication callbacks (and of course, instances on different applications have separate pools of authentication callbacks). The following snippet shows a complete example (replace “<your-app>” with your actual application identifier):

// Create a reference to a Webcom application
try {
    Webcom ref = new Webcom(new WebcomApp("<your-app>"));
    OnAuth listener = new OnAuth() {
        @Override
        public void onComplete(@Nullable AuthResponse response) {
            if (response == null) { // Successfull Logout
                System.out.println("Logout succeeded");
            } else { // Successfull login
                Identity authState = response.getIdentity();
                System.out.println("Authentication succeeded as " + authState.getUid());
            }
        }
        @Override
        public void onError(WebcomError error) {
            System.out.println(error.getMessage());
        }
    };
    ref.registerAuthCallback(listener);
    // { ...
    // Within this fragment, 'listener' is called each time the authentication state changes
    // ... }
} catch (WebcomException e) {
    e.printStackTrace();
}

In Swift, authentication callbacks are functions receiving an AuthenticationEvent parameter.

This type is an enum with three cases:

  • .authenticated indicates that an end user has signed in. This case has an AuthenticationDetails associated value.
  • .notAuthenticated indicates that the end user has signed out. This case does not have an associated value.
  • .rejected indicates that an authentication operation has been rejected. This case has a WebcomError associated value giving the cause of this rejection.

Registering (resp. unregistering) an authentication callback consists in subscribing to (resp. unsubscribing from) an event corresponding to the change of the authentication state. Subscribing is done with the subscribeToChange() of an AuthenticationService object. Unsubscribing is done with the unsubscribe() of the AuthenticationSubscription object returned by the subscription.

The following snippet shows a complete example:

let authenticationService = WebcomApplication.default.authenticationService // application is configured in the `Info.plist` file
authenticationService.subscribeToChange { event in
    // This code is called each time the authentication state changes.
    switch event {
    case let .authenticated(details: details):
        print("successfully authenticated as:", details.uid)
    case .notAuthenticated:
        print("logout succeeded")
    case let .rejected(cause: error):
        print("authentication failed:", error)
    }
}

Limitations

  1. The authentication state is purely local to the client device where the Authentication Service is executed, there is no central state maintained at the Webcom application level.
    For example, if the same user is signed in to your app both on a mobile phone and on a desktop web interface, then signing out from the mobile phone doesn't sign s/he out from the web interface.

  2. Only one end-user can sign in at a time to a given Webcom application on the same device.
    For example, if Mary signs in first to app A on a tablet, and then Peter signs in to app A on the same tablet (within the same user session from the tablet OS viewpoint), then Mary is eventually signed out from app A and Paul signed in to app A.

  3. However, the same end-user can sign in to various applications at a time on the same device.
    For example, Mary can sign in to both apps A and B on her tablet.

  4. The authentication state of a given user for a given Webcom application on a given device is valid until:

    • either the user signs out from this application on this device,
    • or the corresponding authentication token expires.