2

I am using angular 17 standalone. I installed the angular-oauth2-oidc library. It turns out that he doesn't get the token. I have the same angular application in an older version with NgModule and it works fine. Do you know a way to solve the problem? It is also possible to change the library to one that will work with Angular Standalone

export class AppComponent implements OnInit {
    constructor(private oauthService: OAuthService) {
        this.configureOAuth();
    }
    private configureOAuth(): void {
        const authConfig: AuthConfig = {
            issuer: 'url',
            redirectUri: window.location.origin,
            responseType: 'code',
            requireHttps: false,
            clientId: 'm0063',
            scope: 'openid profile email offline_access roles',
        };
        this.oauthService.configure(authConfig);
        //this.oauthService.loadDiscoveryDocumentAndLogin();
    }
    ngOnInit(): void {}

    login() {
        this.oauthService.loadDiscoveryDocumentAndLogin().then(x => {
            setTimeout(() => {
                this.oauthService.initCodeFlow();
            });
        });
    }

    logout() {
        this.oauthService.logOut({ customParameters: true, client_id: 'm0063' });
    }
}

export const appConfig: ApplicationConfig = {
    providers: [
        provideAnimations(),
        provideHttpClient(),
        provideRouter(
            appRoutes,
            withPreloading(PreloadAllModules),
            withInMemoryScrolling({ scrollPositionRestoration: 'enabled' }),
            withViewTransitions()
        ),
        importProvidersFrom(HttpClientModule),
        provideOAuthClient( {
            resourceServer: {
                allowedUrls: ['localhost:4200', 'url:8080'],
                sendAccessToken: true
          }
        }
        ),
        provideUrl(),
}

error:your text Unchecked runtime.lastError: A listener indicated an asynchronous response by returning true, but the message channel closed before a response was received

I trying do new module and implement config as in For.root in ngModule, but it is not working still.

1
  • Same here, in one specific app the oidc 17 doest work with the angular 17. Commented Jan 17, 2024 at 11:10

3 Answers 3

3

I was having a similar problem with this, and while the above solution does work... I have a default 404 page in my solution and this was displaying for a few seconds, before the home page was showing.

So my solution was to use an a "APP_INITIALIZER" to deal with the authentication and then allow the app to render. So this is what i came up with:

auth-initalizer.ts

const authConfig: AuthConfig = {
   issuer: environment.authentication.authority,
   redirectUri: window.location.origin + '/index.html',
   silentRefreshRedirectUri: window.location.origin + '/silent-refresh.html',
   clientId: environment.authentication.appId,
   dummyClientSecret: environment.authentication.appSecret,
   responseType: 'code',
   scope: environment.authentication.scopes,
   showDebugInformation: environment.authentication.showDebug,
   sessionChecksEnabled: environment.authentication.enableSessionChecks,
   requireHttps: environment.authentication.requireHttps,
   silentRefreshShowIFrame: environment.authentication.silentRefreshShowIFrame,
   oidc: true,
   clearHashAfterLogin: false,
   useSilentRefresh: true,
   requestAccessToken: true
};

export function AuthInitalizer(_oauthService: OAuthService, _router: Router) {

return () => {
    _oauthService.configure(authConfig);
    return new Promise((resolve, reject) => {
        initialize(_oauthService).subscribe((loggedIn) => {
            if (!loggedIn) {
                reject('could not login the user');
                return;
            }
            resolve(true);
            if (_oauthService.state) {
                const uri = decodeURIComponent(_oauthService.state);
                _router.navigateByUrl(uri);
            } else {
                _router.navigateByUrl('/');
            }
        })
    });
  };
}

function initialize(_oauthService: OAuthService): Observable<boolean> {
   return new Observable<boolean>((observer) => {

    _oauthService.loadDiscoveryDocumentAndTryLogin().then(_ => {
        if (!_oauthService.hasValidIdToken() || !_oauthService.hasValidAccessToken()) {
            const path = window.location.pathname;
            _oauthService.initCodeFlow(path);
        } else {
            observer.next(true);
            observer.complete();
        }
    });
  });
}

app.config.ts

export const appConfig: ApplicationConfig = {
  providers: [
    provideHttpClient(),
    provideOAuthClient({
      resourceServer: {
        allowedUrls: ['https://api.domain.com'],
        sendAccessToken: true
      }
    }),
    { provide: LocationStrategy, useClass: PathLocationStrategy },
    { provide: APP_INITIALIZER, useFactory: AuthInitalizer, deps: [OAuthService, Router], multi: true, }
  ],
};
Sign up to request clarification or add additional context in comments.

Comments

1

I am using angular 17, angular-oauth2-oidc and keycloak.

This approach worked for me:

    import {Injectable} from '@angular/core';
    import {AuthConfig, OAuthService} from 'angular-oauth2-oidc';
    import {Observable, of} from 'rxjs';
    import {environment} from '../../../environments/environment';

    @Injectable({
      providedIn: 'root',
    })
    export class AuthService {
      constructor(private oauthService: OAuthService) {}

      authConfig: AuthConfig = {
        responseType: 'code',
        scope: 'openid profile email',
        redirectUri: window.location.origin,
        oidc: true,
        requestAccessToken: true,
        showDebugInformation: true,
        strictDiscoveryDocumentValidation: false,
        useSilentRefresh: true,
        issuer: `${environment.KEYCLOAK_URL}realms/${environment.KEYCLOAK_REALM}`,
        clientId: environment.KEYCLOAK_CLIENT_ID,
      };

      initAuth() {
        this.oauthService.configure(this.authConfig);
        this.oauthService.setupAutomaticSilentRefresh();
        this.oauthService.loadDiscoveryDocumentAndTryLogin();
      }

      login() {
        this.initAuth();
        this.oauthService.initCodeFlow();
      }

      logout() {
        this.oauthService.logOut();
      }

      isLoggedIn(): Observable<boolean> {
        return of(this.oauthService.hasValidIdToken());
      }

      getAccessToken(): string {
        const accessToken = this.oauthService.getAccessToken();
        return accessToken;
      }
    }

I provided the oAuth2Lib in my Applicationconfig like this:

    export const coreConfig: ApplicationConfig = {
      providers: [
         provideOAuthClient()
      ]
    }

You may also have to provide the "AuthService" in your standalone app.component.ts and call "initAuth()" within your constructor. I have not found a better solution yet.

export class CoreComponent {
  constructor(
    private readonly authService: AuthService,
  ) {
    this.authService.initAuth();
  }
}

Comments

0

In app.config.ts try to change provideHttpClient() to

      ...  
       provideHttpClient(
          withInterceptors([]),
          withInterceptorsFromDi()
        ),
      ...

For more info check withInterceptorsFromDi()

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.