Using Twitch OAuth with Nebular in Angular

For a friend, I am in the process of developing a custom website using the Nebular package. I want users to log in with their Twitch accounts to access the site, but I am encountering issues with the NbAuthModule. Below is the code snippet:

app.module.ts

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';

import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { NbThemeModule, NbLayoutModule, NbButtonModule, NbIconModule, NbSpinnerModule, NbCardModule } from '@nebular/theme';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { NbEvaIconsModule } from '@nebular/eva-icons';
import { HttpClientModule } from '@angular/common/http';
import { NbAuthModule, NbAuthOAuth2Token, NbOAuth2AuthStrategy, NbOAuth2GrantType } from '@nebular/auth';
import { ChannelComponent } from './pages/channel/channel.component';
import { NbOAuth2CallbackComponent } from './pages/OAuth2/NbOAuth2Callback.component';
import { NbOAuth2LoginComponent } from './pages/OAuth2/NbOAuth2Login.component';

@NgModule({
  declarations: [
    AppComponent,
    ChannelComponent,
    NbOAuth2LoginComponent,
    NbOAuth2CallbackComponent
  ],
  imports: [
    BrowserModule,
    AppRoutingModule,
    BrowserAnimationsModule,
    NbThemeModule.forRoot({ name: 'dark' }),
    NbLayoutModule,
    NbButtonModule,
    NbIconModule,
    NbSpinnerModule,
    NbCardModule,
    NbAuthModule.forRoot({
      strategies:[
        NbOAuth2AuthStrategy.setup({
          clientId:'<cliend-id>',
          clientSecret: '<client-secret>',
          defaultMessages:['Successfully logged in'],
          name:'twitch',
          baseEndpoint:'https://id.twitch.tv/oauth2/',
          redirect:{
            success:'pages/channel',
            failure:'auth/error'
          },
          token:{
            endpoint:'token',
            grantType: NbOAuth2GrantType.AUTHORIZATION_CODE,
            class: NbAuthOAuth2Token,
          },
          authorize:{
            endpoint:'authorize',
            scope:'user_read',
            responseType: 'code',
            redirectUri:'http://localhost:4200/auth/callback'
          },
          refresh:{
            endpoint:'token',
            grantType: NbOAuth2GrantType.REFRESH_TOKEN
          }
        }),
      ]
    }),
    NbEvaIconsModule,
    HttpClientModule,
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

NbOAuth2Login.component.ts

import { Component, OnDestroy } from '@angular/core';
import { NbAuthOAuth2Token, NbAuthResult, NbAuthService } from '@nebular/auth';
import { Subject } from 'rxjs';
import { map, tap, takeUntil} from 'rxjs/operators';

@Component({
    selector: 'nb-oauth2-login',
    template: `
      <button nbButton outline *ngIf="!token" (click)="login()" status="primary" routerLink="auth/login">
      <nb-icon icon="smiling-face-outline"></nb-icon>
        Login
      </button>

      <button nbButton outline *ngIf="token" (click)="logout()">
        Logout
      </button>
    `,
})

export class NbOAuth2LoginComponent implements OnDestroy {
  
    private destroy$ = new Subject<void>();
    // @ts-ignore
    token: NbAuthOAuth2Token;
    
    constructor(private authService: NbAuthService){
      this.authService.onTokenChange()
      .pipe(takeUntil(this.destroy$))
      // @ts-ignore
      .subscribe((token: NbAuthOAuth2Token) => {
          // @ts-ignore
          this.token = null;
          if (token && token.isValid()) {
            this.token = token;
          }
      });
    }
  
    login() {
      this.authService.authenticate('twitch')
        .pipe(takeUntil(this.destroy$))
        .subscribe((authResult: NbAuthResult) => {
        });
    }

    logout() {
      this.authService.logout('twitch')
        .pipe(takeUntil(this.destroy$))
        .subscribe((authResult: NbAuthResult) => {
        });
    }
  
    ngOnDestroy(): void {
      this.destroy$.next();
      this.destroy$.complete();
    }
}

NbOAuth2Callback.component.ts

import { Component, OnDestroy } from '@angular/core';
import { Router } from '@angular/router';
import { NbAuthResult, NbAuthService } from '@nebular/auth';
import { Subject } from 'rxjs';
import { map, tap, takeUntil} from 'rxjs/operators';

@Component({
    selector: 'nb-playground-oauth2-callback',
    template: `
      <nb-layout>
        <nb-layout-column>
        <nb-card [nbSpinner]="true" nbSpinnerSize="giant" nbSpinnerStatus="info">
          <nb-card-body>
            Authenticating...
          </nb-card-body>
        </nb-card>
      </nb-layout-column>
      </nb-layout>
    `,
})

export class NbOAuth2CallbackComponent implements OnDestroy {
  
    private destroy$ = new Subject<void>();
  
    constructor(private authService: NbAuthService, private router: Router) {
      this.authService.authenticate('twitch')
        .pipe(takeUntil(this.destroy$))
        .subscribe((authResult: NbAuthResult) => {
          if (authResult.isSuccess() && authResult.getRedirect()) {
            this.router.navigateByUrl(authResult.getRedirect());
          }
          else{
            this.router.navigateByUrl('auth/error');
          }
        });
    }
  
    ngOnDestroy(): void {
      this.destroy$.next();
      this.destroy$.complete();
    }
  }

I have noticed that the Token is empty when using the Login module in debug mode, but I am unsure of the reason behind this.

Answer №1

In order to resolve this issue, I included 2 additional parameters in app.module.ts using the specified syntax:

...
 token:{
            endpoint:'token?client_secret=<client-secret>',
            grantType: NbOAuth2GrantType.AUTHORIZATION_CODE,
            class: NbAuthOAuth2Token,
            redirectUri: 'http://localhost:4200/auth/callback',
        },
...

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

The type 'void' cannot be assigned to the type 'ReactNode'

Having trouble with the total amount calculation due to the nature of the calculateTotal function import CartItem from "./CartItem" import {CartItemType} from '../App' import {Typography,Stack} from '@mui/material'; type Props ...

Error encountered while bundling CDK Synth with Node.js function - Kindly ensure to update your lock file by running `npm install` before proceeding further

As I attempt to utilize AWS CDK for creating a Lambda function, I am facing a challenging error: "npm ERR! npm ci can only install packages when your package.json and package-lock.json or npm-shrinkwrap.json are in sync. Please update your lock file ...

"Error: Invalid Client - The client_id parameter is missing in the authlib + MailChimp OAuth2

I am currently developing an OAuth2 Factory utilizing authlib and FastAPI to enable my upstream application to authenticate with multiple providers. While the authentication factory functions well with most providers, it encounters issues specifically wit ...

Display a React component according to the user's input

Within the first (parent) div, there is an underlined message stating: "This JSX tag's 'children' prop expects a single child of type 'ReactNode', but multiple children were provided.ts(2746)". import A from './components/A&ap ...

"Alert: The ToastData is nowhere to be found in

In my previous Angular 5 application, I was using ng2-Toasty for displaying toasts. However, since ng2-Toasty does not support Angular 8, I am now trying to switch to ngx-toastr. Upon implementation, I noticed that ngx-toastr does not have an equivalent o ...

Make sure to add the .npmrc file when setting up a fresh Angular project

Currently, I am in the process of developing a command line application with node.js. This specific application is designed to utilize the ng new command from angular CLI. During the creation of a new angular project, dependencies are automatically install ...

MUI Select component not displaying top border

Can anyone help me understand why the select field is behaving this way? I'm new to the project and suspect that someone may have made changes to it. https://i.sstatic.net/pB6Sx.png <mui.FormControl style={{ width: '598px' }}> ...

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 ...

Surveying in TypeScript-React

I am currently working on incorporating a polling feature in React using TypeScript. This polling function is required to make a REST API call to retrieve a record from DynamoDB and then continue polling every 30 seconds until the 'Status' field ...

Having trouble with the removeEventListener OnDestroy not functioning properly in Angular 6 using Javascript?

I have been experimenting with using the removeEventListener function in my Angular component. I came across a helpful discussion on this topic: Javascript removeEventListener not working ... ngOnInit() { document.addEventListener('v ...

Angular 8 Refresh Token Implementation

I am currently working on an Angular 8 app that is integrated with .NET Core. My goal is to find a way to refresh a JWT token within the application. Within the integration, users are able to validate and receive a token which expires after 30 minutes. T ...

Combining Angular subscriptions to fetch multiple data streams

I am looking to retrieve the most recent subscription from a group of subscriptions. Whenever the value of my FormControl changes, I want to capture only the latest value after the user has finished typing. Below is the code snippet I am using - let cont ...

Issue encountered while attempting to initiate a new project with Angular CLI

Encountering an error while trying to create a new app using Angular CLI Attempted solutions: npm cache clean --force npm cache verify Unfortunately, the above steps did not resolve the issue Please refer to the image linked below https://i.sstatic.ne ...

How can you transfer array elements to a new array using JavaScript?

I have a task to transform the fields of an array received from one server so that they can be understood by another server for upload. My approach involves first retrieving and displaying the original field names from the initial server's array to al ...

ng-show directive in AngularJS is not functioning properly when utilized with CLI

After setting up my Angular app with ng new app, I attempted to hide certain elements conditionally using ng-show. Unfortunately, it doesn't seem to be working as expected. <span ng-show="false">Angular App</span> Regardless ...

The API's post call is throwing an error, yet it functions perfectly when tested on

Currently, I have a functional Angular project that connects to real data using WebAPI2. However, I am now working on an Express.js project for demo purposes which mocks the data, providing random information instead of consuming the actual WebAPI2 data. T ...

What is the best way to click on a particular button without activating every button on the page?

Struggling to create buttons labeled Add and Remove, as all the other buttons get triggered when I click on one. Here's the code snippet in question: function MyFruits() { const fruitsArray = [ 'banana', 'banana', & ...

Manipulating Angular and Typescript to utilize the method's parameter value as a JavaScript object's value

I am currently working with Ionic, Angular, and Typescript, attempting to dynamically set the value of a location based on the parameter passed from a method. Here is the relevant code snippet: async fileWrite(location) { try { const result = a ...

Retrieve contextual information within standard providers

I'm currently using nestjs to create a straightforward HTTP rest API, utilizing typeorm. I have set up 2 Postgres databases and would like the ability to access both, although not necessarily simultaneously. Essentially, I am looking to designate whi ...

Utilize various algorithms to identify the predominant object based on multiple parameters in TypeScript

Having collected student profiles with scores in various subjects such as physics, chemistry, and math, I am looking to identify a group of dominant students based on their individual subject scores. For instance: let students = [{name: "A", phy: 70, chem ...