Handling Application Startup
Overview
When we created the application for the getting started tutorial we made sure Identity Vault was properly initialized before we used it. However, we just jumped right into the first tab of the main part of the app. This is not a realistic experience for our users. Let's implement something more realistic.
The Login Page
Our application currently just starts right up in the application itself and we have a button that the user can press to store the authentication information in the vault. This is not realistic. Our application should have a page where the user logs in.
In our case, this will still just be a button that the user presses to fake a log in, but we are getting a step closer to an actual flow by having the login page.
The Startup Flow
When our application starts, the session can be in one of the following states:
- Locked:
- With valid authentication tokens.
- With invalid authentication tokens.
- Not logged in.
If the application is locked, the application shall give the user the opportunity to unlock the vault. If the unlock fails, the user shall be given the option to either try again or to clear the session data and log in again.
If the user unlocks the vault and the resulting authentication information is valid, the first tab shall be loaded. For our tutorial application, if we have session data the session is, by definition, valid.
If the user unlocks the vault and the resulting authentication information is expired, the login page shall be loaded. Having expired or otherwise invalid authentication information is not technically possible in our tutorial application, but we will code for it none the less.
If the user is not logged in, the login page shall be loaded.
We will build upon the application we created in the getting started tutorial in order to implement a basic application startup workflow.
Let's Code
As mentioned previously, this tutorial builds upon the application created when doing the getting started tutorial. If you have the code from when you performed that tutorial, then you are good to go. If you need the code you can make a copy from our GitHub repository.
Generate New Pages
In order to implement our startup and authentication strategies, we need to have a LoginPage
. We will also replace
the "default" page (currently the Tab1Page
) with a StartPage
that will contain our startup logic.
Generate these pages.
Update Routes
With the new pages in place, the routing needs to be fixed. The application's routing scheme has two levels: a base
page level and a sub-page level. As such, each of our routes has one of the following formats: /base-page
or
/base-page/sub-page
.
At the base page level, we want to have three different pages: TabsPage
, LoginPage
, and StartPage
. We also want
the default route (/
) to be the StartPage
. Update the src/app/app.routes.ts
file to:
- Define the
/tabs
route. - Define the
/login
route. - Define the
/start
route. - Create a redirect from
/
to/start
.
The TabsPage
(route: /tabs
) has sub-pages. The sub-pages are already set up, but we need to make the following
adjustments to src/app/tabs/tabs.routes.ts
:
- Remove the redirect for
/
since it was moved tosrc/app/app.routes.ts
. - Change the main path from
tabs
(which is now defined insrc/app/app.routes.ts
) to an empty string.
The AuthenticationService
Part of our startup strategy involves authentication. We will not really be performing authentication, but we will add the service so that we have the infrastructure in place so we can later add authentication via a solution such as Auth Connect.
Generate the authentication service.
An empty service is created.
Inject the SessionVaultService
.
The user needs to be able to log in. Since we do not yet have an authentication strategy, we will store a fake session.
For the logout()
, just clear the stored session.
To determine if the user is authenticated, check for a stored session.
Generate the authentication service.
An empty service is created.
Inject the SessionVaultService
.
The user needs to be able to log in. Since we do not yet have an authentication strategy, we will store a fake session.
For the logout()
, just clear the stored session.
To determine if the user is authenticated, check for a stored session.
We now have an AuthenticationService
that we can use in the rest of our app. We also have a service that we can
update to add our actual authentication services using a solution such as Auth Connect.
The LoginPage
The login page simply includes a "Login" button.
When the button is pressed the following tasks are performed:
- Attempt to log in.
- If the login succeeds, go to the
Tab1Page
. - If the login fails we will just log it for now. When actual authentication is implemented this may be a good place to display a "Login Failed" message, but that is beyond the scope of this tutorial.
Update the SessionVaultService
The startup logic needs to determine if the vault is currently locked and provide a mechanism to unlock the vault
if it is locked. Update the SessionVaultService
to provide unlock()
and isLocked()
methods.
In the isLocked()
method, we are ignoring the actual state for SecureStorage
or InMemory
type vaults because
Identity Vault will report them as "locked" even though they logically cannot lock. This is a long standing quirk
with Identity Vault that would be a breaking change to fix.
The StartPage
We will start with this requirement: If the unlock fails, the user shall be given the option to either try again or to clear the session data and log in again.
This may seem like an odd place to start, but it is the only requirement that involves the look and feel of the page, so let's get that established first.
We are only conditionally showing the "Unlock" and "Redo Login" buttons. For now, we will hard code the condition to not display these buttons. We also removed the header, toolbar and title as we want this page to be minimal. Remove those components, add our new ones, and create empty methods for the bound click handlers.
With the basics in place, let's implement the rest of the logic.
For the unlock flow, we will first attempt an unlock, and then see if we can navigate. Perform this flow when the user navigates to this page.
We will only attempt the unlock operation if the vault is actually locked. Try to unlock the vault. If the unlock fails, set the "show" flag so the user can try again or give up and go back to the login step.
If the user succeeded in unlocking the vault, determine if we should navigate to the LoginPage
or the Tab1Page
based on the current authentication status.
If the user chooses to redo the login, logout and navigate to the LoginPage
.
For the unlock flow, we will first attempt an unlock, and then see if we can navigate. Perform this flow when the user navigates to this page.
We will only attempt the unlock operation if the vault is actually locked. Try to unlock the vault. If the unlock fails, set the "show" flag so the user can try again or give up and go back to the login step.
If the user succeeded in unlocking the vault, determine if we should navigate to the LoginPage
or the Tab1Page
based on the current authentication status.
If the user chooses to redo the login, logout and navigate to the LoginPage
.
One item of note on the redoLogin()
code. If we are using an authentication system, we need to craft our logout()
method such that it can be called with a locked vault. Crafting the logout as such is beyond the scope of this tutorial.
Redirect on Lock
Cleanup the Tab1Page
This step is completely optional. The tutorial application will work perfectly fine with the code as-is. There are
several items in the Tab1Page
that no longer make sense, however, and now is a good time to clean those up. Here is
a synopsis of what can be cleaned up:
- Remove the "Store" button and all code associated with it.
- Change the "Clear" button to a "Logout" button and update the click handler accordingly.
- Remove the "Unlock" button and all code associated with it.
- Remove the code that subscribes to the
locked$
observable and clears the displayed session data when the vault is locked. This is no longer needed because we navigate away from the page entirely when the vault locks.
Cleaning this all up is left as an exercise to the reader but we provide the completed code here for you to compare against.
Next Steps
In this tutorial, we created a good basic application startup workflow. This is an example of a good workflow, but it
is not the only potential flow. For example, our application simply navigates to /tabs/tab1
after unlocking the
vault. You could, however, store information about the current state of the application and then restore to that
state after unlocking the application. Do whatever is right for your application.