Activities of "sumeyye.kurtulus"

Thank you for your clarification.

The reason you see a difference between MVC and Angular is due to the authorization flow being used:

  • MVC app uses the Authorization Code Flow.
    • In this flow, the authentication happens on the server side.
    • When the backend detects that the user’s email is not confirmed, it can directly redirect to the /Account/ConfirmUser page (server-side redirect).
    • That’s why it just works automatically in the MVC app.
  • Angular app is a client-side SPA.
    • If you use Resource Owner Password Flow, the login happens entirely on the Angular side.
    • In this case, there is no server-side redirect — instead, the Angular client receives an error (e.g., inactive user / confirm email required), and it must decide how to handle it (e.g., call /api/account/send-email-confirmation-token and show a confirmation screen).
    • This is why the Angular package does not provide /Account/ConfirmUser out of the box.

In short:

  • Code Flow = backend handles redirects (Blazor, MVC, Razor Pages).
  • Password Flow = frontend must handle errors manually (Angular, SPA).

Here’s a reference explaining the difference between Code Flow and Password Flow in OAuth 2.0:

👉 Auth0 Docs – Authentication and Authorization Flows

Sure, that would be the best if you could provide a minimal example through my e-mail address: sumeyye.kurtulus@volosoft.com.

Hello,

In ABP, two-factor authentication (2FA) is an optional security feature that must be enabled per user. When enabled, after the username and password are verified, the backend does not immediately log the user in. Instead, it responds with a "RequiresTwoFactor" error along with the userId and twoFactorToken. The frontend must then guide the user through the “send security code” and “verify security code” steps to complete login. You can refer to this document: https://abp.io/docs/latest/modules/identity/two-factor-authentication

Normally, 2FA depends on the user having a confirmed email address or phone number, because the second factor is delivered through those channels (or via an authenticator app tied to a confirmed identity).

Could you please clarify:

  • How 2FA has been enabled for users who don’t have a confirmed email/phone?
  • Is 2FA a feature you want us to implement fully in this project, or should we focus only on the email/phone confirmation flow for now?

Thank you for your cooperation.

Could you please specify the cli version you use for creating the project?

Hello Marc,

I am glad to hear you were able to download the example project without any issues. Please feel free to take the time you need to review it — I will be happy to receive your feedback whenever it is convenient for you.

Regarding the Navbar problem, it could indeed be resolved by aligning the implementation with the example. If not, please open another ticket, and we will look into it further.

Thank you for the update, and I look forward to your thoughts once you have had a chance to explore the project.

Hello again,

Thank you for your patience and cooperation. We will be fixing this problem in the next patch version.

You can follow the process here: https://github.com/abpframework/abp/issues/23610, https://github.com/abpframework/abp/releases

Until then, I can suggest you to modify this file temporarily

// node_modules/@abp/ng.schematics/utils/model.js

exports.resolveAbpPackages = resolveAbpPackages;
function renamePropForTenant(interfaces) {
    for (const inters of interfaces) {
        for (const prop of inters.properties) {
            const isTenant = prop.name.toLocaleLowerCase().includes(constants_1.TENANT_KEY);
            const isSaasDto = prop.refs.filter(f => f.startsWith(constants_1.SAAS_NAMESPACE)).length > 0;
            // you need to add `!prop.type.startsWith('Saas')` to avoid duplication
            if (isTenant && isSaasDto && !prop.type.startsWith('Saas')) {
                prop.type = 'Saas' + prop.type;
            }
        }
    }
}

I am also processing a refund for your ticket.

Hello,

You can refer to this up-to-date documentation for custom layout usage for lepton-x components: https://abp.io/docs/latest/ui-themes/lepton-x/how-to-use-lepton-x-components-with-angular-custom-layout

Other than that I can replace the navbar and footer using this technique as it was the same in the previous versions:

export class AppComponent {
  replacableComponent = inject(ReplaceableComponentsService);

  constructor() {
    this.replacableComponent.add({
      key: eThemeLeptonXComponents.Navbar,
      component: MyNavbar,
    });
    this.replacableComponent.add({
      key: eThemeLeptonXComponents.Footer,
      component: MyFooter,
    });
  }
}

If you think that your problem is something else, I can assist you further.

Hello,

You will need to eliminate manual route configuration by automatically generating both application routes and sidebar navigation based on your data.

The structure actually works like this

  1. Application Routes (app.routes.ts)
    • Handles actual page navigation
    • Loads components when URLs are accessed
    • Defines the routing structure
  2. Sidebar Navigation (route.provider.ts)
    • Manages ABP sidebar menu items
    • Dynamically adds/removes navigation links
    • Keeps menu in sync with available routes

I am sending a sample project for you to provide a better guidance: https://drive.google.com/file/d/1dSL9Aqm17E35LKPn-KxVDS0RZpF_n6IR/view?usp=drive_link

Here in this project:

  • RouteManagerService handles sidebar updates
  • ExampleService manages data and route generation
  • RouteDemoComponent provides visual testing interface

You can let us know if you need further assistance. Thank you for your cooperation.

We will be adding full support for this builder in the next version. Please keep in mind that Angular may have compatibility issues with the latest updates compared to our packages.

In the meantime, we are also reviewing related packages that could introduce problems in upcoming patch releases, so fixes may be applied before the next major version. You can track our progress here: https://github.com/abpframework/abp/issues/23608 https://github.com/abpframework/abp/releases

Hello, We will be fixing this problem for the next studio release where you can follow from this link https://abp.io/docs/latest/studio/release-notes

Until we release a fix, you can follow these steps to make your application work. I will also be sending a sample project having the same fixes.

  • Update your Environment.ts to separate the authentication flow from the host application as follows
// ...
// Separate the API and AuthServer URLs
const apiUrl = `http://${yourIP}:44331`;
const oAuthIssuer = `http://${yourIP}:44327`;

const dev = {
  apiUrl,
  appUrl: `exp://${yourIP}:19000`,
  oAuthConfig: {
    issuer: oAuthIssuer,
    clientId: 'Ticket9786_Mobile',
    scope: 'offline_access Ticket9786',
  },
  localization: {
    defaultResourceName: 'Ticket9786',
  },
} as Environment;

const prod = {
  apiUrl,
  appUrl: `exp://${yourIP}:19000`,
  oAuthConfig: {
    issuer: oAuthIssuer,
    clientId: 'Ticket9786_Mobile',
    scope: 'offline_access Ticket9786',
  },
  localization: {
    defaultResourceName: 'Ticket9786',
  },
} as Environment;
// ...
  • Replace your UseAuthAndTokenExchange.ts as follows
import * as WebBrowser from 'expo-web-browser';

import { store } from '../store';
import AppActions from '../store/actions/AppActions';
import PersistentStorageActions from '../store/actions/PersistentStorageActions';
import { getEnvVars } from '../../Environment';
import { makeRedirectUri } from 'expo-auth-session';

const {
  oAuthConfig: { issuer, clientId, scope },
} = getEnvVars();

const useAuthAndTokenExchange = navigation => {
  const handleAuthentication = async () => {
    try {
      // For tiered architecture: open AuthServer in browser
      // AuthServer will handle OAuth and redirect back to React Native

      const redirectUri = makeRedirectUri();

      const authUrl =
        `${issuer}/connect/authorize?` +
        `client_id=${clientId}&` +
        `redirect_uri=${encodeURIComponent(redirectUri)}&` +
        `response_type=code&` +
        `scope=${encodeURIComponent(scope)}&` +
        `state=${Math.random().toString(36).substring(7)}`;

      const result = await WebBrowser.openAuthSessionAsync(authUrl, redirectUri);

      if (result.type === 'success') {
        // Parse the redirect URL to get authentication data
        const url = new URL(result.url);
        const code = url.searchParams.get('code');

        if (code) {
          // For tiered architecture, we need to establish the authenticated session
          // This could be by exchanging the code for a token, or by getting user context

          // Option 1: Exchange code for token (if the app needs to make API calls)
          try {
            const tokenEndpoint = `${issuer}/connect/token`;
            const tokenResponse = await fetch(tokenEndpoint, {
              method: 'POST',
              headers: {
                'Content-Type': 'application/x-www-form-urlencoded',
              },
              body: new URLSearchParams({
                grant_type: 'authorization_code',
                client_id: clientId,
                code: code,
                redirect_uri: redirectUri,
              }).toString(),
            });

            if (tokenResponse.ok) {
              const tokenData = await tokenResponse.json();

              // Store the token for future API calls
              store.dispatch(
                PersistentStorageActions.setToken({
                  token_type: tokenData.token_type || 'Bearer',
                  access_token: tokenData.access_token,
                  refresh_token: tokenData.refresh_token,
                  expire_time: new Date().valueOf() + tokenData.expires_in * 1000 || 0,
                  scope: tokenData.scope,
                }),
              );

              // After establishing the session, fetch app config to get current user
              store.dispatch(AppActions.fetchAppConfigAsync({ showLoading: false }));
              navigation.navigate('Home');
            } else {
              console.error('💥 Failed to establish authenticated session');
            }
          } catch (error) {
            console.error('💥 Error establishing authenticated session:', error);
          }
        } else {
          console.error('💥 No authorization code in redirect URL');
          console.error('💥 Full redirect URL:', result.url);
        }
      } else if (result.type === 'cancel') {
        console.log('🚀 ~ Auth cancelled by user');
      } else {
        console.log('🚀 ~ Auth result type:', result.type);
      }
    } catch (error) {
      console.error('💥 Error in authentication flow:', error);
    }
  };

  return { handleAuthentication };
};

export default useAuthAndTokenExchange;

  • Update your db migrator to use your IP instead just for the mobile client, then rerun the migration.
// src/YourProject.DbMigrator/appsettings.json
{
  "ConnectionStrings": {
    "Default": "mongodb://localhost:27017/Ticket9786"
  },
  "Redis": {
    "Configuration": "127.0.0.1"
  },
  "OpenIddict": {
    "Applications": {
      // ...
      },
      "Ticket9786_Mobile": {
        "ClientId": "Ticket9786_Mobile",
        "RootUrl": "exp://192.168.1.39:19000"
      },
      "Ticket9786_BlazorServer": {
        "ClientId": "Ticket9786_BlazorServer",
        "ClientSecret": "1q2w3e*",
        "RootUrl": "https://localhost:44385"
      },
      "Ticket9786_Swagger": {
        "ClientId": "Ticket9786_Swagger",
        "RootUrl": "https://localhost:44331/"
      }
    }
  }
}

  • Add this configuration to the preconfigure services in auth server module
 #if DEBUG
        PreConfigure<OpenIddictServerBuilder>(options =>
        {
            options.UseAspNetCore()
                .DisableTransportSecurityRequirement();
        });
 #endif
  • I suggest you to use Kestrel configuration for the development phase, so you can update the development settings as follows
// src/YourProject.AuthServer/appsettings.Development.json
{
  "Kestrel": {
    "Endpoints": {
      "Http": {
        "Url": "http://0.0.0.0:44327"
      }
    }
  }
}

// src/YourProject.HttpApi.Host/appsettings.Development.json
{
  "Kestrel": {
    "Endpoints": {
      "Http": {
        "Url": "http://0.0.0.0:44331"
      }
    }
  },
  "AuthServer": {
    "Authority": "http://192.168.1.39:44327",
    "MetaAddress": "http://192.168.1.39:44327",
    "RequireHttpsMetadata": false,
    "Audience": "Ticket9786"
  }
}

You can let us know if you need further assistance. Thank you for your cooperation.

Showing 61 to 70 of 460 entries
Boost Your Development
ABP Live Training
Packages
See Trainings
Mastering ABP Framework Book
The Official Guide
Mastering
ABP Framework
Learn More
Mastering ABP Framework Book
Made with ❤️ on ABP v10.1.0-preview. Updated on November 04, 2025, 06:41