Setting up Identity Server 4 integration with Ionic 2

Currently, I am in the process of setting up Identity Server to function with Ionic 2. I am a little confused about how to set up the Redirect URLs specifically for testing purposes in the browser.

Furthermore, I am updating and integrating an OIDC Cordova component. The previous version of the component can be found on GitHub here: https://github.com/markphillips100/oidc-cordova-demo

I have developed a typescript provider and have successfully registered it with my app.module.ts

import { Injectable } from '@angular/core';
import { Observable } from 'rxjs/Rx';
import 'rxjs/add/operator/map';
import { Component } from '@angular/core';
import * as Oidc from "oidc-client";
import { Events } from 'ionic-angular';
import { environment } from "../rules/environments/environment";

export class UserInfo {
    user: Oidc.User = null;
    isAuthenticated: boolean = false;
}

@Injectable()
export class OidcClientProvider   {

    USERINFO_CHANGED_EVENT_NAME: string = ""
    userManager: Oidc.UserManager;
    settings: Oidc.UserManagerSettings;
    userInfo: UserInfo = new UserInfo();
    constructor(public events:Events) {

        this.settings = {
            //authority: "https://localhost:6666",
            authority: environment.identityServerUrl,
            client_id: environment.clientAuthorityId,
            //This doesn't work
            post_logout_redirect_uri: "http://localhost/oidc",
            redirect_uri: "http://localhost/oidc",
            response_type: "id_token token",
            scope: "openid profile",

            automaticSilentRenew: true,
            filterProtocolClaims: true,
            loadUserInfo: true,
            //popupNavigator: new Oidc.CordovaPopupNavigator(),
            //iframeNavigator: new Oidc.CordovaIFrameNavigator(),
        }

        this.initialize();
    }

    userInfoChanged(callback: Function) {
        this.events.subscribe(this.USERINFO_CHANGED_EVENT_NAME, callback);
    }

    signinPopup(args?): Promise<Oidc.User> {
        return this.userManager.signinPopup(args);
    }

    signoutPopup(args?) {
        return this.userManager.signoutPopup(args);
    }

    protected initialize() {

        if (this.settings == null) {
            throw Error('OidcClientProvider required UserMangerSettings for initialization')
        }

        this.userManager = new Oidc.UserManager(this.settings);
        this.registerEvents();
    }

    protected notifyUserInfoChangedEvent() {
        this.events.publish(this.USERINFO_CHANGED_EVENT_NAME);
    }

    protected clearUser() {
        this.userInfo.user = null;
        this.userInfo.isAuthenticated = false;
        this.notifyUserInfoChangedEvent();
    }

    protected addUser(user: Oidc.User) {
        this.userInfo.user = user;
        this.userInfo.isAuthenticated = true;
        this.notifyUserInfoChangedEvent();
    }

    protected registerEvents() {
        this.userManager.events.addUserLoaded(u => {
            this.addUser(u);
        });

        this.userManager.events.addUserUnloaded(() => {
            this.clearUser();
        });

        this.userManager.events.addAccessTokenExpired(() => {
            this.clearUser();
        });

        this.userManager.events.addSilentRenewError(() => {
            this.clearUser();
        });
    }
}

I am aiming to comprehend the process of configuring the redirect URLs for authentication to work smoothly in the browser. Generally, a redirect URL is set to handle the token and claims post-login.

this.settings = {
        authority: environment.identityServerUrl,
        client_id: environment.clientAuthorityId,
        post_logout_redirect_uri: "http://localhost:8100/oidc",
        redirect_uri: "http://localhost:8100/oidc",
        response_type: "id_token token",
        scope: "openid profile AstootApi",

        automaticSilentRenew: true,
        filterProtocolClaims: true,
        loadUserInfo: true,
        //popupNavigator: new Oidc.CordovaPopupNavigator(),
        //iframeNavigator: new Oidc.CordovaIFrameNavigator(),
    }

Since Ionic 2 does not make use of URLs for routing, suppose I have a component AuthenticationPage responsible for storing the authentication token. How can I set up a redirect URL to navigate to the authentication page for testing purposes in the browser?

Answer №1

Summary

In order to make this work, I had to make some adjustments.
Initially, I didn't realize that my Redirect URLs needed to match what was stored in the identity server for the client.

new Client
{
    ClientId = "myApp",
    ClientName = "app client",
    AccessTokenType = AccessTokenType.Jwt,
    RedirectUris = { "http://localhost:8166/" },
    PostLogoutRedirectUris = { "http://localhost:8166/" },
    AllowedCorsOrigins = { "http://localhost:8166" },
    //...
}

Therefore, the OIDC client in Typescript also needed to be updated.

this.settings = {
    authority: environment.identityServerUrl,
    client_id: environment.clientAuthorityId,
    post_logout_redirect_uri: "http://localhost:8166/",
    redirect_uri: "http://localhost:8166/",
    response_type: "id_token token",
}

Additionally, since I didn't want to set up routing in Ionic, I needed to find a way for a URL to communicate with Ionic (for browser testing purposes, while normal communication would be done through Cordova).

Therefore, I set the redirect URL to the URL where Ionic hosts my application, and in app.Component.ts in the Constructor, I added code to attempt to retrieve my authentication token.

constructor(
  public platform: Platform,
  public menu: MenuController,
  public oidcClient: OidcClientProvider
)
{
  //Hack: since Ionic only has 1 default address, attempt to verify if this is a call back before calling 
   this.authManager.verifyLoginCallback().then((isSuccessful) => {
     if (!isSuccessful) {
        this.authManager.IsLoggedIn().then((isLoggedIn) => {
          if (isLoggedIn) {
              return;
          }

          this.nav.setRoot(LoginComponent)
        });
     }
  });
}

Update Verify login callback should just be the OIDC client callback which will retrieve the token from the GET params

verifyLoginCallback(): Promise<boolean> {
    return this.oidcClient.userManager.signinPopupCallback()
        .then(user => {
            return this.loginSuccess(user).
                then(() => true,
                    () => false);
    }, err => { console.log(err); return false; });
} 

NOTE the Login component is simply a modal representing the login landing page, with a login button to initiate the popup. You can integrate this with any user-driven event to trigger the login, but a user-driven event must be used to avoid triggering a popup blocker on the web

<ion-footer no-shadow>
  <ion-toolbar no-shadow position="bottom">
    <button ion-button block (click)="login()">Login</button>
  </ion-toolbar>
</ion-footer>

login(): Promise<any> {
    return this.oidcClient.signinPopup().then((user) => {
        this.events.publish(environment.events.loginSuccess);
    }).catch((e) => { console.log(e); });
}

I'm sure there are better ways to redirect to a different route, but this was a quick solution for now.

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

Is React Context malfunctioning due to a syntax error?

Using the function "login" from React context is causing an error for me: const handleLogin = async (data: LoginType) => { try { await login(auth, data.email, data.password); router.push("/Dashboard"); } catch (error: an ...

View the picture directly on this page

Currently, I am in the process of creating a gallery and I would like the images to open on top of everything in their original size when clicked by the user. My expertise lies in HTML and CSS at the moment, but I am open to learning JavaScript and jQuery ...

Obtain a sanitized response object from a POST request using Restangular

Having an issue with the Restangular service. When making a POST request, the response Object contains all the Restangular methods which I don't want. I just need a clean response without any extra methods. Any suggestions on how to achieve this? th ...

Is there a way to rotate label text on a radar chart using chart js?

I am working with a Chart js radar diagram that contains 24 labels. My goal is to rotate each label text by 15 degrees clockwise from the previous one: starting with 'Label 1' at the top in a vertical position, then rotating 'Label 2' ...

Having trouble rendering Next.JS dynamic pages using router.push()? Find out how to fix routing issues in your

The issue I am facing revolves around the visibility of the navbar component when using route.push(). It appears that the navbar is not showing up on the page, while the rest of the content including the footer is displayed. My goal is to navigate to a dy ...

Encountering an issue with React and material-ui-pickers date-io Jalaali Utils: receiving a TypeError stating that utils.getDayText is not recognized as

This issue is different from what was discussed in https://github.com/mui-org/material-ui-pickers/issues/1440 because I am not facing any problems with the original implementation. Referencing the link provided here , I have utilized JalaliUtils from @da ...

Accessing information independent of Observable data in TypeScript

When attempting to send an HttpRequest in Typescript, I encountered an issue where the received data could not be stored outside of the subscribe function. Despite successfully saving the data within the subscribe block and being able to access it there, ...

Best Practices for Updating UI State in Client Components Using NextJS and Server Actions

My goal is to create a page using nextjs 14 that functions as a stock scanner. This page will retrieve data from an external API using default parameters, while also offering users the ability to customize parameters and re-run the scan to display the resu ...

Can you summarize HTML DOM and jQuery DOM in a single sentence?

I've encountered a challenge while working on my Javascript code with a HTML5 canvas and jQuery. I am currently using getElementById to access the canvas and $('canvas') to apply a jQuery function to it. The issue arises when I realize that ...

Retrieve an item from a mapped array

Currently, I am using the following code snippet console.log('errors: ' + password.get('errors')); to check the output from password.get('errors'));, and in the console, the response is as follows: List [ Map { "id": "validat ...

Is there a way to properly structure a JSON file for easy reading on localhost

I am having trouble with the formatting of my .json file while using backbone.js. I can't seem to pass in the url correctly. PlayersCollection = Backbone.Collection.extend({ model: Player, url: 'http://localhost/STEPS/data/players.js ...

When the input field is cleared, JavaScript will not be able to recognize its contents

Having an issue with my function that fetches results, <script language="javascript"> function fetchResult(value){ url="ajax_fetch.php?st=usr&q="+value; ajax(url); } fetchResult(" "); </script&g ...

Unable to modify the background image of a div using jQuery

I'm encountering an issue in my script where I tried to implement an event that changes the background-image of a div when a button is clicked, but it's not functioning as intended. Below is the code snippet: HTML <div class="col-md-2 image ...

How to format a Date object as yyyy-MM-dd when serializing to JSON in Angular?

I have a situation where I need to display an object's 'birthDate' property in the format DD/MM/YYYY on screen. The data is stored in the database as YYYY-MM-DD, which is a string type. I am currently using bootstrap bsDatePicker for this ta ...

Tips for Managing Disconnection Issues in Angular 7

My goal is to display the ConnectionLost Component if the network is unavailable and the user attempts to navigate to the next page. However, if there is no network and the user does not take any action (doesn't navigate to the next page), then the c ...

Updating the main window in Angular after the closure of a popup window

Is it possible in Angular typescript to detect the close event of a popup window and then refresh the parent window? I attempted to achieve this by including the following script in the component that will be loaded onto the popup window, but unfortunatel ...

Error: Trying to use 'setTimeout' before it has been initialized is not allowed

I'm currently working on a JavaScript exercise in my code. I encountered an issue where I am trying to assign a reference to the setTimeout function to ogTimeout on the second line since I plan to redefine setTimeout later. However, when I run the co ...

Is the Dropbox JavaScript SDK compatible with Ionic3?

Does anyone know how to integrate the Dropbox JavaScript SDK into an Ionic 3 app? Just a note: I have come across some sample examples using the http endpoint. ...

When utilizing Google Analytics in conjunction with Next.Js, encountering the error message "window.gtag is not

Encountering an error on page load with the message: window.gtag is not a function Using Next.js version 14.0.4. All existing solutions seem to hinder data collection, preventing the website from setting cookie consent correctly. I am uncertain about the ...

Tips for utilizing the selected option in the name attribute with Javascript or jQuery

I am looking to use the "selected" attribute in the option element based on the name attribute using JavaScript or jQuery. Essentially, I want the option with name="1" to be automatically selected when the page loads. I have attempted the following code, b ...