Identity-TBD

Documentation Page

Identity-TBD is an API service that provides Identity-as-a-service (IDAAS) features for your app development.

Save yourself the hassle and security worries of a old-fashioned name/password login scheme and give your application a modern, professional sign-in experience that leverages the Single-Sign-In services of many favorite providers, such as Google, Facebook, Apple, and more.

Getting Started

Identity-TBD is available from the RapidAPI marketplace.

Pick your plan and make requests as shown on the RapidAPI site. Remember to use your rapidApi api key in the headers of the request as shown.

BYOB (Bring your own browser)

If your app is a web page (SPA or otherwise), you are already in a browser context. If your app is a mobile app, you may first need to create a webview control to host the login experience, and then follow the steps shown here within that context. Once you have your identifier, you no longer need to remain in the webview.

The OAuth2 login process used for each of the providers differs slightly per provider, but all will employ a combination of service requests and browser redirects to conduct the secure login using their infrastructure and user information. This is why a browser context is necessary to conduct the sign-in process.

Identity-TBD normalizes all of the variations for you, so the process is the same regardless which provider your user selects.

The overall flow

In this diagram, the calls to the rest-api for /login and /identity are controlled as they are in the helper library, identity-tbd-client.js which will be explored in more detail shortly.

On page load

The login process is driven on entry by the presence or absence of a token, named idtbd that determines the next steps. If this code is available, it is used to call the /identity endpoint with to retrieve the associated IdentityObject. If it is not available, the next step is to call the /login endpoint which will return HTML that should be put into the browser page to allow the user to select their login provider and continue the sign-in process.

The Login Process

The result from the login request will be HTML content. This content should be set to your browser (use document.write()). This Page will direct the user to select from a list of possible providers and then proceed to execute the sign-in process via that provider.

When the process completes, it will redirect to the page url where the login request was made, and this redirect request will include a query parameter named idtbd (e.g. http://localhost:8081/index.html?idtbd=xxxxxxxx) The value of the idtbd parameter can be used as a token to retrieve the Identity data from the service, with the /identity api.

The /login endpoint accepts a single path parameter, appId

Picking an appId

An appId is an arbitrary string, but it should be unique to avoid possible duplication of identifiers with another app.

The recommendation is to use reverse domain notation - such as com.example.your-app-name where the reverse-domain portion represents a domain identifying your organization, if possible.

The Identity Process

After the login process delivers an idtbd token to the page, this token may be used to retrieve the actual IdentityObject and its associated identifying information. The /identity endpoint is called by passing this idtbd value as a path parameter (e.g.) /identity/28ca232d-d09f-461e-9a04-3e5217f92c10.

This call does not return HTML, but a JSON response (Content-Type 'application/json') that contains the so-called IdentityObject At this point you can pull the information needed from this object (most notably the userIdentity value) and use as appropriate in your own app code.

Using the identity-tbd-client.js library

You could choose to implement Identity-TBD for your application at the REST-API level, but you may find it much easier to use the helper script identity-tbd-client.js, or the minified version (identity-tbd-client-min-js), or if you are creating a React app and need an ES6 module for this, the @tremho/idtbd module available from NPM.

The following sections walk through the flow explained above, and in particular references the flow chart diagram, but in this description, we look through the lens of using the client library. Afterward, some sample app implementations are presented to help you get started.

1. OnLoad

On page load, the application checks for an idtbd token value passed into it by either a query parameter on the URL or as a cookie. If this value exists, the login selection itself may be skipped and the identity for the token is retrieved.

2. Login

if no identity token is available, the login selection may begin. This can be designed to occur directly at this point, or upon a button click from the user. This login operation produces html that is delivered to the brower and conducts the remaining steps of the provider-specific sign-in flow, after which the page from the caller is refreshed, this time with an idtbd value made available.

3. Identity

With an idtbd token in hand, a call to the /identity operation is made and a complete IdentityObject is returned. This object contains information from the provider about the signed-in user, but more importantly a unique yet consistent userIdentity value that identifies this user to your application. At this point, your app can use this identifier to establish a user presence within your application, establish a session, access your database, etc. as the needs of your app define.

Implementing the javascript identity-tbd-client library

Below is some sample code for a simple HTML page that implements the identity-tbd-client.js library.


            <!DOCTYPE html>
            <html lang="en">
            <head>
                <meta charset="UTF-8">
                <title>Simple Example</title>
                <script src="https://www.tremho.com/identity-tbd/script/identity-tbd-client-min.js" type="application/javascript"></script>
                <script>
                  const rapidapikey = '---your-rapid-api-key-here---'
                  const appId = 'simpleTest'
                  function start(withLogin) {
                    window.IDTBD.allowCookie = true
                    window.IDTBD.onLoad(rapidapikey,appId,onIdentity,onStatus).then(() => {
                      console.log("return from onLoad", window.IDTBD)
                      if(withLogin) {
                        window.IDTBD.login()
                      }
                    })
                  }
                  function onIdentity(identityObject) {
                    console.warn('called with ', identityObject)
                    document.getElementById('identity').innerText=`User Identity returned as ${identityObject.userIdentity}`
                  }
                  function onStatus(status) {
                    console.log(status)
                    let vis = status ? 'hidden' : 'visible'
                    if(status === 'Logout') vis = 'visible'
                    document.getElementById('login').style.visibility = vis
                    if(status === 'Identified') vis = 'visible'
                    document.getElementById('logout').style.visibility = vis
                  }
                </script>
            </head>
            <body onload="start(false)">

            <h1>Simple example</h1>
            <button id='login' onClick="window.IDTBD.login()">Log in</button>
            <button id='logout' onClick="window.IDTBD.logout()">Log Out</button>
            <p id='identity'/>

            </body>
            </html>
    

Before running the above code, replace the '---your-rapid-api-key-here---' with your actual rapidAPI api key. Otherwise, you will get an error in the javascript console and the page will not execute.

When run, this page will present a "Log in" and a "Log Out" button. Logging in will begin the sign-in process and once complete, the user identifier will be displayed.

Understanding the code

The implementation begins by loading the identity-tbd-client-min.js script, which we can see with this line within the <head> section of the html.

              <script src="https://www.tremho.com/identity-tbd/script/identity-tbd-client-min.js" type="application/javascript"></script>
            
there are minimized and non-minimized versions of this script available, each identical in operation When this script is loaded, it will be available in the window namespace IDTBD. It will be referred to subsequently via window.IDTBD in the page script.

Creating the execution script section

Immediately following the script load, there is a <script> section defined. This is where the page interacts with the library and its layout elements. In this example, it begins with a start function. We can see further down that the <body> tag invokes this function through its `onload` handler, so that the execution occurs when the page is ready.

We see the `start` function immediately calling window.IDTBD.onLoad and passing the following parameters

Optional components to the start function

You've no doubt notices that the example code start function accepts a parameter named withLogin that is called as 'false' when invoked from the "<body onload=" trigger. If this were called as 'true', then login would be called when the onLoad promise returns, eliminating the need for a Log In button. The user would automatically be prompted to select their provider on page load, unless there was a cookie stored, in which case the identity callback would announce the returning user with no futher interaction.

Also, you will note the line window.IDTBD.allowCookie=true. This is optional since the default for this value is 'true', but were it to be set to false, then the standard behavior of using a cookie to capture the last idtbd would be skipped, and the user will need to log in each time. The need to Log Out would also be eliminated.

Implement according to the needs of your app and any user preferences for cookie usage.

Implementing for React

If you are working in React, please look at the following example, written in Typescript and using NPM modules, while keeping in mind what we learned from the simple HTML example above.

MainPage.tsx

        import React  from 'react'
        import { Button } from "@mui/material"
        import IDTBD from '@tremho/idtbd'

        export default function MainPage() {
          const [identity, setIdentity] = React.useState(null)
          const [status, setStatus] = React.useState('')

          const rapidapikey = '---your-rapid-api-key-here---'
          const appId = 'com.example.yourApp'
          const withLogin = false

          function callback(identity) {
            console.warn('callback called with', identity)
            setLoggedInUser(identity)
          }
          function statusCallback(status) {
            console.log("status", status)
            setStatus(status)
          }

          React.useEffect( () => {
            if(!identity) {
              IDTBD.allowCookie = true
              IDTBD.onLoad(rapidapikey, appId, callback, statusCallback).then(() => {
                console.log("return from onLoad", IDTBD)
                if (withLogin) {
                  IDTBD.login()
                }
              })
            }
          })

          async function setLoggedInUser(identity:any) {
            console.warn("SetLoggedInUser", identity)
            setIdentity(identity)
            // you can now do what you may need to do for your own app with this identity
          }

          function UserIdentity() {
            if(identity?.userIdentity) {
              return (
                <>
                  <p>user identity = {identity?.userIdentity}</p>
                </>
              )
            }
          }

          // supress page output if status callback informed us we are in process, or we have no identity
          if(!status || identity)
            return  (
              <>
                <h3>Identity-TBD React sample</h3>

                <div>
                  <Button onClick={IDTBD.login} className="btn btn-primary">Log In</Button>
                  <Button onClick={IDTBD.logout} className="btn btn-primary">Log Out</Button>
                </div>
                <UserIdentity />
              </>
            )
        }

Here, we can see features introduced in the previous example, but couched within React-type contexts.

First, we see that the IDTBD object has been imported as an ES6 module, so we refer to it by this name alone, rather than window.IDTBD

The module can be found on NPM and is installed with npm install @tremho/idtbd

We see our identityCallback and statusCallback functions defined, and following through we see that these echo these status changes via useState so that React state management is properly executed.

We see the "start" function from the html example is effectively reproduced here within the useEffect handler that React will update with each state change. As in the previous example, we pass our rapidapikey, appId, and callbacks to the onLoad function to set things up.

What to do when you get an identifier

In these examples, we are simply displaying the value of the identifier to the web page, but in an actual app, you will want to initiate some mechanism (perhaps via your backend services) to establish a session or other context that will use this user identifier within your app. The actual use of this will depend upon your application architecture and your database and service implementation.

Provider Data

The IdentityObject contains a property named providerData. Within this will be one or more object properties that have the names of the provider that supplied this information via their sign-in process. These property names will be 'apple', 'google', 'facebook' (and others as new providers are added). Each will contain an object that at a minimum will contain a providerToken identifier, but may also contain properties that contain some direct personal information about the user (depending upon the provider and the options the user has set with that provider). These may include email, name, and/or picture information. The structure of this information varies by provider and not all fields may exist.

For most of the providers, the providerToken value may be used to access the provider-specific apis of that provider to obtain a potentially wider degree of information to discover about the user. Visit the developer documentation sites for each of the providers to learn more about using their apis. It is recommended that information you may need to collect for the user be done within your application, although the provider info may be used to pre-populate the fields of such an on-boarding form.

Log Out

The "log out" operation merely removes the value of the cookie that is saved (if cookies are enabled). You can do this by calling IDTBD.logout, as shown here, or simply with document.cookie='idtbd='

Provider Linking

Not shown in either of these examples is handling the IDTBD.link operation. This is used to associate the currently logged in identity with the sign-in result of using a different provider.

To use link, you must first have performed the onLoad operation and established an IdentityObject from a login

Call link in the way that you would call login, except you must pass the sid property found in the IdentityObject as the idtbd parameter to link. This will proceed through a flow very similar to that of login, but upon the successful conclusion, the browser window will contain the words 'Identities Linked' and subsequent logins via either the original provider or through the new linked provider will result in the same userIdentity value. The providerData information will contain entries for all the linked providers, by name.