Unable to Get Callback URL to work in Angular 5

  • Which SDK does this apply to? (Ex: auth-node)

Angular 5

  • Which version of the platform are you facing this error on? (Ex: Node 6.4)
    Angular 5

  • Was this code working before? Have you made any changes in the dashboard recently?
    It has never worked

  • Please capture and attach the stacktrace, it helps a lot!
    Error message from the console is listed below

  • Please share the code that is causing the error.
    See below

  • Can you share a minimum reproducible?
    Yes

  • Please capture and attach a HAR from the browser if this is an Authentication Bug / Issue.
    Not sure what that is

  • If this is a Management API Client bug, some libraries allow you to capture a HAR.

After user logs in, I continue to get this error message:

ERROR Error: Uncaught (in promise): Error: Cannot match any routes. URL Segment: ‘access_token’
Error: Cannot match any routes. URL Segment: ‘access_token’
at ApplyRedirects.push…/node_modules/@angular/router/fesm5/router.js.ApplyRedirects.noMatchError (router.js:1326)
at CatchSubscriber.selector (router.js:1307)
at CatchSubscriber.push…/node_modules/rxjs/_esm5/internal/operators/catchError.js.CatchSubscriber.error

The error goes on and on. But, I always get this error message. I set up the Callback URL to be something other then the home page.

But it always goes back to the Home page.

Below is the home page:
http://localhost:4200/

Below is the callback page I want to use:
http://localhost:4200/#/portal-home

But it never works. Note, I even added this URL to the list of the callback URLs in the Application.

Any ideas what is wrong?

Below is the code for reference (note for space when I cut-n-paste the code it added #32 everywhere. I can email code to someone if that will make it easier):

Any help is much appreciated.

Thanks.

Variable Code File:
src\app\auth\auth0-variables.ts
interface AuthConfig {
clientID: string;
domain: string;
callbackURL: string;
callbackURLDevelopment: string;
}

export const AUTH_CONFIG: AuthConfig = {
clientID: ‘d7ghOqaAbwvdT5D5pe7gebJs2p9OvAuH’,
domain: ‘genphygrp.auth0.com’,
callbackURL: ‘http://test.genesisdocs.org/’,
callbackURLDevelopment: ‘http://localhost:4200/#/portal-home
// callbackURL: ‘http://genonline.centralus.cloudapp.azure.com/callback

};

Auth Service Code file:
import { Injectable } from ‘@angular/core’;
import { AUTH_CONFIG } from ‘./auth0-variables’;
import { environment } from ‘…/…/environments/environment’;
import { Router } from ‘@angular/router’;
import { Globals } from ‘…/globals’;

import * as auth0 from ‘auth0-js’;

(window as any).global = window;

@Injectable()
export class AuthService {

userProfile: any;
requestedScopes: string = ‘openid profile read:employment-ads edit:employment-ads’;
profile: any;
public genRole: string;
public nickName: string;
public siteName: string;

auth0 = new auth0.WebAuth({
clientID: AUTH_CONFIG.clientID,
domain: AUTH_CONFIG.domain,
responseType: ‘token id_token’,
audience: https://${AUTH_CONFIG.domain}/userinfo,
redirectUri: environment.production === true ? AUTH_CONFIG.callbackURL : AUTH_CONFIG.callbackURLDevelopment,
// redirectUri: AUTH_CONFIG.callbackURL,
scope: this.requestedScopes
});

constructor(
public router: Router,
public globals: Globals
) {
console.log('Angular Production Mode = ’ + environment.production);
}

public login(): void {
this.auth0.authorize();
}

public handleAuthentication(): void {
this.auth0.parseHash((err, authResult) => {
console.log(‘In handleAuthentication in auth.service.ts’);
if (authResult && authResult.accessToken && authResult.idToken) {
this.setSession(authResult);
this.getProfile((err2, profile) => {
this.profile = profile;
console.log(‘this.profile.name=’);
console.log(this.profile.name);
console.log(‘this.profile.nickname=’);
console.log(this.profile.nickname);
console.log(‘this.profile[https://gpg.com]=’);
console.log(this.profile[‘https://gpg.com’]);
this.globals.userLogin = this.profile.name;
console.log(‘this.globals.userLogin=’);
console.log(this.globals.userLogin);
});
this.router.navigate([‘/home’]);
} else if (err) {
this.router.navigate([‘/home’]);
console.log(err);
alert(Error: ${err.error}. Check the console for further details.);
}
});
}

public userRoles(scopes: Array<string>): boolean {
const grantedScopes = JSON.parse(localStorage.getItem(‘scopes’)).split(’ ');
return scopes.every(scope => grantedScopes.includes(scope));
}

public getProfile(cb): void {
const accessToken = localStorage.getItem(‘access_token’);
if (!accessToken) {
throw new Error(‘Access token must exist to fetch profile’);
}

const self = this;
this.auth0.client.userInfo(accessToken, (err, profile) => {
if (profile) {
self.userProfile = profile;
console.log(‘profile from auth.service.ts’);
console.log(profile);
console.log(self.userProfile.name);
console.log(self.userProfile.nickname);
console.log(self.userProfile[‘https://gpg.com’]);
this.genRole = self.userProfile[‘https://gpg.com’];
console.log('this.genRole = ’ + this.genRole);
this.nickName = self.userProfile.nickname;
console.log('this.nickName = ’ + this.nickName);
this.siteName = self.userProfile[‘https://sitename.com’] || this.nickName;
console.log('this.siteName = ’ + this.siteName);
}
cb(err, profile);
});
}

private setSession(authResult): void {
// Set the time that the access token will expire at
const expiresAt = JSON.stringify((authResult.expiresIn * 1000) + new Date().getTime());

// If there is a value on the scope param from the authResult,
// use it to set scopes in the session for the user. Otherwise
// use the scopes as requested. If no scopes were requested,
// set it to nothing
const scopes = authResult.scope || this.requestedScopes || ‘’;
console.log(‘authResult.scope from auth.service.ts’);
console.log(authResult.scope);

localStorage.setItem(‘access_token’, authResult.accessToken);
localStorage.setItem(‘id_token’, authResult.idToken);
localStorage.setItem(‘expires_at’, expiresAt);
localStorage.setItem(‘scopes’, JSON.stringify(scopes));
}

public logout(): void {
// Remove tokens and expiry time from localStorage
localStorage.removeItem(‘access_token’);
localStorage.removeItem(‘id_token’);
localStorage.removeItem(‘expires_at’);
localStorage.removeItem(‘scopes’);
// Go back to the home route
this.router.navigate([‘/’]);
}

public isAuthenticated(): boolean {
// Check whether the current time is past the
// access token’s expiry time
const expiresAt = JSON.parse(localStorage.getItem(‘expires_at’) || ‘{}’);
return new Date().getTime() < expiresAt;
}

public userHasScopes(scopes: Array<string>): boolean {
const grantedScopes = JSON.parse(localStorage.getItem(‘scopes’)).split(’ ');
return scopes.every(scope => grantedScopes.includes(scope));
}

}

Hi @juan.vega
The OAuth2 spec does not allow any fragment in the callback URL. So even though you provide http://localhost:4200/#/portal-home as the callback page, Auth0 will be redirecting to http://localhost:4200/ (it strips anything after the hash).
Since the implicit flow returns the authentication result in the fragment, what you end up getting is something like http://localhost:4200/#access_token=...{and the rest of the auth result}.

You’ll need to handle the results (parseHash) in the root or in a separate path (e.g. /callback).

Hope that clarifies it.