- ABP Framework version: v7.4.5
- UI Type: Angular
- Database System: EF Core (SQL Serve)
- Tiered (for MVC) or Auth Server Separated (for Angular): yes/
- Implemting SSO I have implemented Okta SSO and obtained the ID Token from Okta. I have also installed the following packages:
@okta/okta-angular (v6.4.0) @okta/okta-auth-js (v7.10.1)
Authentication is working as expected, as confirmed by the following check:
this.oktaAuth.isAuthenticated().then(async (authStatus) => {
    if (authStatus) {
        // Authenticated successfully
    }
});
Additionally, I can successfully invoke APIs using this authentication setup but not check authorization with different role:
context.Services.AddAuthentication(options =>
{
    options.DefaultAuthenticateScheme = "MultipleAuthSchemes";
    options.DefaultChallengeScheme = "MultipleAuthSchemes";
})
.AddPolicyScheme("MultipleAuthSchemes", JwtBearerDefaults.AuthenticationScheme, options =>
{
    options.ForwardDefaultSelector = context =>
    {
        string? authorization = context.Request.Headers["Authorization"];
        if (!string.IsNullOrEmpty(authorization) && authorization.StartsWith("Bearer "))
        {
            var token = authorization.Substring("Bearer ".Length).Trim();
            return token.Contains("okta") ? "okta_jwt_schema" : JwtBearerDefaults.AuthenticationScheme;
        }
        return JwtBearerDefaults.AuthenticationScheme;
    };
})
.AddJwtBearer(JwtBearerDefaults.AuthenticationScheme, options =>
{
    options.Authority = configuration["AuthServer:Authority"];
    options.RequireHttpsMetadata = Convert.ToBoolean(configuration["AuthServer:RequireHttpsMetadata"]);
    options.Audience = "Project42";
})
.AddJwtBearer("okta_jwt_schema", options =>
{
    options.Authority = configuration["Okta:Authority"];
    options.RequireHttpsMetadata = Convert.ToBoolean(configuration["Okta:RequireHttpsMetadata"]);
    options.Audience = "api://default";
    options.TokenValidationParameters = new TokenValidationParameters
    {
        ValidateIssuerSigningKey = true,
        ValidIssuer = "https://dev-96317405.okta.com/oauth2/default",
        ValidAudience = "api://default",
        ValidateLifetime = true
    };
});
Now, I have route guards set up as follows:
{
    path: '',
    pathMatch: 'full',
    component: DashboardComponent,
    canActivate: [AuthGuard, PermissionGuard, RoleGuard],
}
I believe these guards require the ABP token instead of the Okta token. How can I properly pass authentication to AuthGuard and PermissionGuard while ensuring authorization in the system using Okta?
Can I do something like if authenticated then logged in with the user by matching the email but I don't know the password I have this method this.authService .login({ username, password, rememberMe })
if I can login into the system without password or similar method in backend then I believe i can login the user with proper abp login and can just authenticate with okta.
44 Answer(s)
- 
    0
- 
    0Hello, yes you are right. You will need to handle this part according to the library you use. The permission guard only checks the required permissions that you give for the route. However, dashboard component checks for MyProjectName.Dashboard.HostandMyProjectName.Dashboard.Tenantpermissions exceptionally.Here is the reference for the check: https://github.com/abpframework/abp/blob/2201ee1c349da9dff2a0a333434e660f436b0851/npm/ng-packs/packages/core/src/lib/guards/permission.guard.ts#L47 
- 
    0Hi sumeyye, I'm using okta-angular library but what I need to do to get response from https://localhost:44345/api/abp/application-configuration?includeLocalizationResources=false like the below ss  also this also I have seen this because this token is of okta open id  what i need to do that this method give me result true this.oAuthService.hasValidAccessToken() 
- 
    0I am assuming that oAuthService is from angular-oauth2-oidclibrary. So, you should be able to use this as you have mentioned at the beginningthis.oktaAuth.isAuthenticated().then(async (authStatus) => { if (authStatus) { // Authenticated successfully } });
- 
    0I configured oAuthConfig in environment.ts oAuthConfig: { issuer: 'https://localhost:44345', redirectUri: baseUrl, clientId: 'Project42_App', scope: 'offline_access Project42', }, and for the okta login const authConfig = { issuer: 'https://dev-******.okta.com/oauth2/default', clientId: '----', redirectUri: window.location.origin + '/login/callback', scopes: ['openid', 'profile', 'email'], pkce: true, } I believe due to two different configurations this.oAuthService.hasValidAccessToken() is resulting false in case of okta. so what you suggest in case of okta I'm thinking you are saying like this below async hasLoggedIn(): Promise<boolean> { const authStatus = await this.oktaAuth.isAuthenticated(); return authStatus || this.oAuthService.hasValidAccessToken(); } this.authService.hasLoggedIn().then(isLoggedIn => { }); 
- 
    0also I need this as well I'm using okta-angular library but what I need to do to get response from https://localhost:44345/api/abp/application-configuration?includeLocalizationResources=false like the below ss  in this query what I believe is the difference is in case of okta I'm sending okta token else abp access token in bearer auth 
- 
    0I'm thinking you are saying like this below async hasLoggedIn(): Promise<boolean> { const authStatus = await this.oktaAuth.isAuthenticated(); return authStatus || this.oAuthService.hasValidAccessToken(); } this.authService.hasLoggedIn().then(isLoggedIn => { }); Yes, this is what I mean. For the granted policies response that you shared, the okta library should not cause a problem. However, I did not see <MyProjectName>.Dashboard.Hostand<MyProjectName>.Dashboard.Tenantpermissions that is checked by the guard. Is this right?
- 
    0I believe I don't have such conditions <MyProjectName>.Dashboard.Host and <MyProjectName>.Dashboard.Tenant also I need this as well I'm using okta-angular library but what I need to do to get response from https://localhost:44345/api/abp/application-configuration?includeLocalizationResources=false like the below ss  in this query what I believe is the difference is in case of okta I'm sending okta token else abp access token in bearer auth 
- 
    0
- 
    0The authGuardalso utilizes theangular-oauth2-oidclibrary, as I mentioned earlier. You can refer to the implementation here: https://github.com/abpframework/abp/blob/dev/npm/ng-packs/packages/oauth/src/lib/guards/oauth.guard.tsSince authGuardfollows the logic of this library, you may need to adjust or replace it based on your specific authentication flow.Regarding permissionGuard, it should not cause any issues. Could you verify your logic and let me know if the issue persists?
- 
    0Hi I'm going to write this custom guard, correct me if i'm wrong, thanks. import { Injectable } from '@angular/core'; import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, Router, } from '@angular/router'; import { Observable } from 'rxjs'; import { OktaAuthService } from './okta-auth.service'; // Your OktaAuthService import { OAuthService } from 'angular-oauth2-oidc'; // ABP's OAuthService @Injectable({ providedIn: 'root', }) export class CustomAuthGuard implements CanActivate { constructor( private oktaAuthService: OktaAuthService, private oAuthService: OAuthService, private router: Router ) {} canActivate( route: ActivatedRouteSnapshot, state: RouterStateSnapshot ): Observable<boolean> | Promise<boolean> | boolean { return this.checkAuthentication(state.url); } private async checkAuthentication(returnUrl: string): Promise<boolean> { const isOktaAuthenticated = await this.oktaAuthService.isAuthenticated(); const hasValidAccessToken = this.oAuthService.hasValidAccessToken(); if (isOktaAuthenticated || hasValidAccessToken) { return true; } else { // Redirect to your custom login page or handle unauthenticated access this.router.navigate(['/login'], { queryParams: { returnUrl } }); return false; }} } 
- 
    0
- 
    0Hi I'm going to write this custom guard, correct me if i'm wrong, thanks. import { Injectable } from '@angular/core'; import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, Router, } from '@angular/router'; import { Observable } from 'rxjs'; import { OktaAuthService } from './okta-auth.service'; // Your OktaAuthService import { OAuthService } from 'angular-oauth2-oidc'; // ABP's OAuthService @Injectable({ providedIn: 'root', }) export class CustomAuthGuard implements CanActivate { constructor( private oktaAuthService: OktaAuthService, private oAuthService: OAuthService, private router: Router ) {} canActivate( route: ActivatedRouteSnapshot, state: RouterStateSnapshot ): Observable<boolean> | Promise<boolean> | boolean { return this.checkAuthentication(state.url); } private async checkAuthentication(returnUrl: string): Promise<boolean> { const isOktaAuthenticated = await this.oktaAuthService.isAuthenticated(); const hasValidAccessToken = this.oAuthService.hasValidAccessToken(); if (isOktaAuthenticated || hasValidAccessToken) { return true; } else { // Redirect to your custom login page or handle unauthenticated access this.router.navigate(['/login'], { queryParams: { returnUrl } }); return false; }} } Hello again, your implementation is correct, but using both OktaAuthService and OAuthService might be redundant unless your app requires multiple authentication providers (e.g., Okta for some users and OAuth2 for others). If both services are needed, consider abstracting authentication logic into a single service to simplify maintenance. Otherwise, removing the unnecessary check can reduce complexity. 
- 
    0Hi I need to implement users can use okta and OAuth2 both. correct me if I'm wrong, thanks. import { Injectable } from '@angular/core'; import { OktaAuthService } from './okta-auth.service'; // Your existing OktaAuthService import { OAuthService } from 'angular-oauth2-oidc'; // OAuthService from angular-oauth2-oidc to simplify logic I created Service for authentication logic @Injectable({ providedIn: 'root', }) export class UnifiedAuthService { constructor( private oktaAuthService: OktaAuthService, private oAuthService: OAuthService ) {} async isAuthenticated(): Promise<boolean> { const isOktaAuthenticated = await this.oktaAuthService.isAuthenticated(); const hasValidAccessToken = this.oAuthService.hasValidAccessToken(); return isOktaAuthenticated || hasValidAccessToken; } } here is the CustomAuthGuard import { Injectable } from '@angular/core'; import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, Router, } from '@angular/router'; import { UnifiedAuthService } from './unified-auth.service'; // The unified authentication service @Injectable({ providedIn: 'root', }) export class CustomAuthGuard implements CanActivate { constructor( private unifiedAuthService: UnifiedAuthService, private router: Router ) {} async canActivate( route: ActivatedRouteSnapshot, state: RouterStateSnapshot ): Promise<boolean> { const isAuthenticated = await this.unifiedAuthService.isAuthenticated(); if (isAuthenticated) { return true; } else { // Redirect to your custom login page or handle unauthenticated access this.router.navigate(['/login'], { queryParams: { returnUrl: state.url } }); return false; } } } 
- 
    0I'm using abp-nav-items 
 in the abp-nav-items I have the logout button so now do I need to write custom component for SSO to logout?Logout process should also require another custom logic. Here is how you can manage that part: import { UserMenuService } from '@abp/ng.theme.shared'; import { eUserMenuItems } from '@volosoft/abp.ng.theme.lepton-x'; import { APP_INITIALIZER, inject, NgModule } from '@angular/core'; @NgModule({ ... providers: [ ... { provide: APP_INITIALIZER, useFactory: userMenuFactory }, ... ], bootstrap: [AppComponent], }) export class AppModule {} function userMenuFactory() { const userMenu = inject(UserMenuService); userMenu.patchItem(eUserMenuItems.Logout, { action: () => { console.log('Custom logout action'); }, }); }
- 
    0
- 
    0Could you also try replacing the component like this https://abp.io/docs/latest/framework/ui/angular/component-replacement#how-to-replace-a-component import { ReplaceableComponentsService } from '@abp/ng.core'; import { Component, inject } from '@angular/core'; import { eThemeLeptonXComponents } from '@volosoft/abp.ng.theme.lepton-x'; import { MySettingsComponent } from './my-settings/my-settings.component'; @Component({ selector: 'app-root', template: ` <abp-loader-bar></abp-loader-bar> <abp-dynamic-layout></abp-dynamic-layout> <abp-gdpr-cookie-consent></abp-gdpr-cookie-consent> `, }) export class AppComponent { private replaceComponent = inject(ReplaceableComponentsService); constructor() { this.replaceComponent.add({ component: MySettingsComponent, key: eThemeLeptonXComponents.Toolbar, }); } }
- 
    0Hi, I'll get back to you soon. I'm currently working on setting things up with Okta, and once that's done, I'll have a few questions for you. Thanks! In the meantime, I do have one question—my application supports multiple grant types for OAuth login, but Okta has fewer grant types configured. Could this potentially impact the application flow? Everything seems to be working fine for now. 
- 
    0It shouldn't, but you can let us know if there is a problem. We are waiting to hear from you for now. 





 
                                