I need assistance with using the angular-oauth2-oidc library to retrieve data from an asynchronous storage provider and then pass it to a synchronous storage implementation

Typically, the angular-oauth2-oidc library saves tokens in session storage by default.

While you can provide your own storage provider through the OAuthStorage class, it requires a storage provider that can retrieve data synchronously.

I am developing a mobile hybrid app using Ionic and CapacitorJS, and I need to store tokens using the CapacitorJS Storage plug-in.

The CapacitorJS Storage plug-in only allows asynchronous data retrieval methods, such as:

get(options: GetOptions) => Promise<GetResult>

This poses a challenge when integrating with the synchronous expectations of the angular-oauth2-oidc library. For instance, their method to fetch an access token follows this pattern:

 public getAccessToken(): string {
    return this._storage ? this._storage.getItem('access_token') : null;
 }

Is there a way for me to create an implementation of the OAuthStorage class with a synchronous getItem method that can utilize the asynchronous CapacitorjS.Storage.get method?

Alternatively, is it possible to convert data from an asynchronous method to be compatible with a synchronous method without altering the caller?

Answer №1

It is impossible to wait for an asynchronous method to finish within a synchronous one, so the task you are inquiring about cannot be achieved directly. Below, you will find a suboptimal workaround that attempts to address this issue.

The following class serves as a synchronous facade for Capicitor's Storage API. From the consumer's perspective, it may seem like multiple keys are being used, but in reality, only one entry is created in storage. This design allows for the underlying keys stored to remain unknown at startup as they are children of the known key. Whenever data is modified, the Storage API reflects these changes.

export class StorageFacade {
  private data: Record<string, any> = {};

  constructor(private storageKey: string) { }
  
  /** Load initial data from storage */
  async init() {
    const res = await Storage.get(this.storageKey);
    this.data = (res) ? JSON.parse(res) : {};
  }  

  getItem(key: string) {
    return this.data[key];
  }

  removeItem(key: string) {
    delete this.data[key];
    Storage.set(this.storageKey, JSON.stringify(this.data));
  }

  setItem(key: string, value: any) {
    this.data[key] = value;
    Storage.set(this.storageKey, JSON.stringify(this.data));
  }
}

The challenge remains of ensuring everything is ready before the keys are required for authentication. One solution is to utilize an APP_INITIALIZER to preload the initial data into storage so that it is prepared prior to any authentication needs:

async function initAuthStorage(storage: OAuthStorage) {
  await this.storage.init();
}

@NgModule({
  providers: [
    { provide OAuthStorage, useValue: new StorageFacade('authStorage') }
    {
      provide: APP_INITIALIZER,
      useFactory: initAuthStorage,
      deps: [OAuthStorage],
      multi: true,
    },
  ],
})

There may be opportunities to refine this approach, such as persisting changes only when the app is closing rather than after every modification. Nonetheless, this should serve as a solid foundation.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Efficiently loading Ionic 3 components within a tab with lazy-loading functionality

Need help with adding a new tab to your project using lazy-loading? You can utilize the @IonicPage decorator for setting up a page as the root of a tab. To implement this, create a new page: // module import { NgModule } from '@angular/core'; ...

Tips for managing the 'completed' button in an Android keyboard application using AngularJS/Ionic

Currently, I am working on developing a hybrid mobile application using AngularJS, Cordova, and the Ionic framework. Check out this Android 5.0 keyboard with a distinct blue button located at the bottom-right corner. https://i.stack.imgur.com/Tfija.png ...

Different approach to including labels on scatter plot without relying on "chartjs-plugin-datalabels"

I need help adding labels to the pink scatter dots without affecting the green bars in the horizontal bar chart generated by ngchart. You can see an image of the chart here. Whenever I try to include the following code: import ChartDataLabels from "c ...

The Karma testing feature in Angular Quickstart encounters issues right from the start

When attempting to run karma tests after a clean install of the official Angular quickstart on Windows 10, I encountered an issue. Following a series of four commands, here is what happened: C:\projects\temp>git clone https://github.com/angul ...

What is the recommended module to choose when importing MAT_DIALOG_DATA?

When working on my Angular project, I noticed that there are multiple options available for importing MAT_DIALOG_DATA. I have tried importing both @angular/material and @angular/material/dialog, and found that both options work successfully. However, I a ...

Material UI - The array is unexpectedly resetting to contain 0 elements following an onChange event triggered by the TextField component

As I work on developing an application, one of the key features involves allowing users to select others from a list with whom they can create a group chatroom. Additionally, there is a TextField where they can assign a name to their newly created group. ...

Using a custom TypeScript wrapper for Next.js GetServerSideProps

I developed a wrapper for the SSR function GetServerSideProps to minimize redundancy. However, I am facing challenges in correctly typing it with TypeScript. Here is the wrapper: type WithSessionType = <T extends {}>( callback: GetServerSideProps&l ...

Develop a set of matching key/value pairs using TypeScript

Looking to develop a custom data type where InputKeys will serve as the keys, and the values will be key/value pairs. The keys should correspond to InputFieldKey, with the value being a string. My current progress includes {[key: string]: string}, but I n ...

Learn the proper way to write onClick in tsx with Vue 2.7.13

current version of vue is 2.7.13 Although it supports jsx, I encounter a type error when using onClick event handling. The type '(event: MouseEvent) => Promise<void>' cannot be assigned to type 'MouseEvent' Is there a correct ...

The Ghostly Glare of Doom: Ionic 2 Strikes on Android

While my application runs smoothly in the browser, I encounter an error when trying to run it on my device. The issue is as follows: 0 758771 log deviceready has not fired after 5 seconds. 1 758797 log Channel not fired: onDOMConte ...

Guide on transitioning Angular 2 RC 1 (or an earlier version) Forms to the new Forms in Angular 2 RC 2 / RC 4

I am currently in the process of upgrading my Angular 2 RC 1 app to Angular 2 RC 4, and part of this update involves migrating my existing forms to Angular 2 RC 4 New Forms. Could someone provide guidance on how to successfully update my existing forms to ...

Ways to set the className prop for all components automatically without having to specify it repeatedly

One challenge I face is dealing with code duplication whenever I create a new component. Is there a way to pass the className property between components without having to explicitly define it every time a new component is created? For example, when I cr ...

What is the process for generating a dynamic array in typescript?

Looking to create a TypeScript dynamic array with the desired format: const display = [ { id: 1, displayName: "Abc1" }, { id: 2, displayName: "Abc2" }, { id: 3, displayName: "Abc3" } ] Attempted the following code ...

What is the process for changing the text in a text box when the tab key on the keyboard is pressed in

When a user types a name in this text box, it should be converted to a specific pattern. For example, if the user types Text@1, I want to print $[Text@1] instead of Text@1$[Text@1]. I have tried using the keyboard tab button with e.keyCode===9 and [\t ...

The script resource is experiencing a redirect that is not permitted - Service Worker

I have integrated a Service Worker into my Angular application, and it works perfectly when running on localhost. However, when I attempt to deploy the code in a development or different environment, I encounter the following error: Service worker registra ...

Modifying the color of a GIF animated image using CSS

I'm currently working on an Angular application and I have a transparent GIF Loader image that I downloaded. I've been trying to figure out how to change the color of the GIF image, but so far, I've only been successful in resizing it. I sea ...

Error: Reference to an undeclared variable cannot be accessed. TypeScript, Cordova, iOS platforms

Can anyone offer some advice on what might be the issue? I'm encountering an error while building my Ionic app on the IOS platform, but everything is running smoothly on Android. ReferenceError: Cannot access uninitialized variable. service.ts:31 O ...

Unexpected outcome when returning a map

Encountered a puzzling issue that requires immediate clarification. When I input the following code into my project: this.metadata = json.metadata.map((x) => {return new Metadatum(x);}); console.log(this.metadata[0].value); The output consistently sho ...

What is the best way to reduce the size of TypeScript source code in an Electron application with the help of Electron Forge and Electron Packager

resolved: I was able to solve this issue using electron-builder, which utilizes webpack in the background to handle all problems efficiently. Initially, I faced this challenge while using electron-forge and electron-packager. Despite researching extensivel ...

Angular-Slickgrid displaying empty data entries

Currently, I am attempting to implement a grid option in my application using the angular slickgrid library. Despite referencing the wiki page for guidance on displaying the grid, I am facing the issue of no data appearing in the grid, and there are no err ...