Open Closed

Can't configure email confirmation token provide with 6 digit for validation #9961


User avatar
0
consultant.ahmet.ulusoy created
  • Template: microservice
  • Created ABP Studio Version: 1.0.1
  • Current ABP Studio Version: 1.3.2
  • Multi-Tenancy: Yes
  • UI Framework: mvc
  • Theme: leptonx
  • Theme Style: system
  • Theme Menu Placement: side
  • Database Provider: ef
  • Database Management System: postgresql
  • Mobile Framework: react-native
  • Public Website: Yes
  • Include Tests: Yes
  • Dynamic Localization: Yes
  • Kubernetes Configuration: Yes
  • Grafana Dashboard: Yes
  • Use Local References: No
  • Selected Languages: English, English (United Kingdom), 简体中文, Español, العربية, हिन्दी, Português (Brasil), Français, Русский, Deutsch (Deuthschland), Türkçe, Italiano, Čeština, Magyar, Română (România), Svenska, Suomi, Slovenčina, Íslenska, 繁體中文
  • Default Language: English
  • Create Command: abp new TavTechnologies.Treva -t microservice --ui-framework mvc --mobile react-native --database-provider ef --database-management-system postgresql --theme leptonx --skip-migrator --public-website --dont-run-bundling -no-language-management -chat -file-management

Hello Dear Abp Team,

We changed token validation times for OpenIdDict with below code

private void PreConfigureOpenIddict(IConfiguration configuration, IWebHostEnvironment hostingEnvironment) { PreConfigure<OpenIddictBuilder>(builder => { builder.AddValidation(options => { options.AddAudiences("AuthServer"); options.UseLocalServer(); options.UseAspNetCore(); }); });

if (!hostingEnvironment.IsDevelopment())
{
    PreConfigure&lt;AbpOpenIddictAspNetCoreOptions&gt;(options =>
    {
        options.AddDevelopmentEncryptionAndSigningCertificate = false;
    });

    PreConfigure&lt;OpenIddictServerBuilder&gt;(serverBuilder =>
    {
        serverBuilder.AddProductionEncryptionAndSigningCertificate("openiddict.pfx", configuration["AuthServer:CertificatePassPhrase"]!);
        serverBuilder.SetIssuer(new Uri(configuration["AuthServer:Authority"]!));

        serverBuilder.SetAuthorizationCodeLifetime(TimeSpan.FromMinutes(2));
        serverBuilder.SetAccessTokenLifetime(TimeSpan.FromHours(1));
        serverBuilder.SetDeviceCodeLifetime(TimeSpan.FromMinutes(2));
        serverBuilder.SetIdentityTokenLifetime(TimeSpan.FromMinutes(30));
        serverBuilder.SetRefreshTokenLifetime(TimeSpan.FromDays(14));
        serverBuilder.SetUserCodeLifetime(TimeSpan.FromMinutes(2));
    });
}

}

Also, we changed PasswordResetTokenProvider to DefaultEmailProvider for sending 6 digit codes and validate them. below code and also set Validation Time to 2 minutes.

private static void ConfigureTokenProviders(ServiceConfigurationContext context) { context.Services.Configure<DataProtectionTokenProviderOptions>(options => { //options.Name = "EmailConfirmationTokenProvider"; options.Name = TokenOptions.DefaultEmailProvider; options.TokenLifespan = TimeSpan.FromMinutes(2); });

context.Services.Configure&lt;SecurityStampValidatorOptions&gt;(options =>
{
    options.ValidationInterval = TimeSpan.FromMinutes(2);
});

context.Services.Configure&lt;IdentityOptions&gt;(options =>
{
    options.Tokens.EmailConfirmationTokenProvider = TokenOptions.DefaultEmailProvider;
    options.Tokens.PasswordResetTokenProvider = TokenOptions.DefaultEmailProvider;
    options.Tokens.ChangeEmailTokenProvider = TokenOptions.DefaultEmailProvider;
    options.Tokens.ChangePhoneNumberTokenProvider = TokenOptions.DefaultEmailProvider;
    //options.Tokens.AuthenticatorTokenProvider = TokenOptions.DefaultEmailProvider;
});

}

But when we call verify password reset token with 6 digit code it validates all the time except when a new one created.

How can i also validate expiration time to for given token with user?


8 Answer(s)
  • User Avatar
    0
    AI-Bot created
    Support Team ABP Agent

    To configure the email confirmation and password reset token providers in ABP Framework to use a 6-digit code and enforce the expiration time, you need to ensure that:

    1. You are using the correct token provider (EmailTokenProvider<TUser>) for email confirmation and password reset.
    2. The TokenLifespan is set as desired (e.g., 2 minutes).
    3. The token validation logic checks the expiration as expected.

    Key Points

    • The EmailTokenProvider<TUser> generates a 6-digit numeric code by default.
    • The TokenLifespan property controls the expiration, but the token provider must be correctly configured and used.
    • If tokens are always validating except for the most recent, it may be due to caching, clock skew, or not using the correct provider when generating/validating tokens.

    Correct Configuration Example

    // In your module's ConfigureServices method:
    context.Services.Configure<DataProtectionTokenProviderOptions>(options =>
    {
        options.TokenLifespan = TimeSpan.FromMinutes(2);
    });
    
    context.Services.Configure<IdentityOptions>(options =>
    {
        options.Tokens.EmailConfirmationTokenProvider = TokenOptions.DefaultEmailProvider;
        options.Tokens.PasswordResetTokenProvider = TokenOptions.DefaultEmailProvider;
        options.Tokens.ChangeEmailTokenProvider = TokenOptions.DefaultEmailProvider;
        options.Tokens.ChangePhoneNumberTokenProvider = TokenOptions.DefaultEmailProvider;
    });
    

    Important: Use the Correct Token Provider

    When generating and validating tokens, always specify the provider:

    // Generating a token
    var token = await _userManager.GenerateUserTokenAsync(user, TokenOptions.DefaultEmailProvider, "ResetPassword");
    
    // Validating a token
    var isValid = await _userManager.VerifyUserTokenAsync(user, TokenOptions.DefaultEmailProvider, "ResetPassword", token);
    

    Troubleshooting

    • If tokens are not expiring as expected, ensure that the TokenLifespan is not being overridden elsewhere.
    • Make sure the system clocks are synchronized across your servers (especially in distributed/microservice setups).
    • If you are using distributed cache for identity, ensure cache invalidation is working as expected.

    References

    This approach aligns with official ABP documentation and common ASP.NET Core Identity practices. If you follow the above configuration and always specify the provider when generating and validating tokens, the expiration should be enforced as expected.


    This response was generated by AI. If it didn’t solve your problem, feel free to post a new answer — our support team will jump in to help you soon.

  • User Avatar
    0
    consultant.ahmet.ulusoy created

    We checked the codes, there is not any code block that sets TokenLifespan except options.TokenLifespan = TimeSpan.FromMinutes(2);

    I'm checking it in my local computer.

    How can I check "distributed cache for identity, ensure cache invalidation is working as expected"?

  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    hi

    But when we call verify password reset token with 6 digit code it validates all the time except when a new one created.

    What is your code?

    Thanks.

  • User Avatar
    0
    consultant.ahmet.ulusoy created
    public virtual async Task<BasicUserInfoDto> TrevaSendPasswordResetCodeAsync(TrevaSendPasswordResetCodeDto input)
    {
        var user = await UserManager.FindByEmailAsync(input.Email) ?? 
            throw new UserFriendlyException(L["Volo.Account:InvalidEmailAddress", input.Email]);
    
        var resetToken = await UserManager.GeneratePasswordResetTokenAsync(user);
    
        await _trevaAccountEmailer.TrevaSendPasswordResetCodeAsync(user, resetToken);
    
        return new BasicUserInfoDto
        {
            UserId = user.Id,
            TenantId = user.TenantId
        };
    }
    
    public override async Task<bool> VerifyPasswordResetTokenAsync(VerifyPasswordResetTokenInput input)
    {
        var user = await UserManager.GetByIdAsync(input.UserId);
        return await UserManager.VerifyUserTokenAsync(
            user,
            UserManager.Options.Tokens.PasswordResetTokenProvider,
            UserManager<Volo.Abp.Identity.IdentityUser>.ResetPasswordTokenPurpose,
            input.ResetToken);
    }
    
  • User Avatar
    0
    consultant.ahmet.ulusoy created
    /// <summary>
    /// Generates a password reset token for the specified <paramref name="user"/>, using
    /// the configured password reset token provider.
    /// </summary>
    /// <param name="user">The user to generate a password reset token for.</param>
    /// <returns>The <see cref="Task"/> that represents the asynchronous operation,
    /// containing a password reset token for the specified <paramref name="user"/>.</returns>
    public virtual Task<string> GeneratePasswordResetTokenAsync(TUser user)
    {
        ThrowIfDisposed();
        return GenerateUserTokenAsync(user, Options.Tokens.PasswordResetTokenProvider, ResetPasswordTokenPurpose);
    }
    
    /// <summary>
    /// Returns a flag indicating whether the specified <paramref name="token"/> is valid for
    /// the given <paramref name="user"/> and <paramref name="purpose"/>.
    /// </summary>
    /// <param name="user">The user to validate the token against.</param>
    /// <param name="tokenProvider">The token provider used to generate the token.</param>
    /// <param name="purpose">The purpose the token should be generated for.</param>
    /// <param name="token">The token to validate</param>
    /// <returns>
    /// The <see cref="Task"/> that represents the asynchronous operation, returning true if the <paramref name="token"/>
    /// is valid, otherwise false.
    /// </returns>
    public virtual async Task<bool> VerifyUserTokenAsync(TUser user, string tokenProvider, string purpose, string token)
    {
        ThrowIfDisposed();
        ArgumentNullThrowHelper.ThrowIfNull(user);
        ArgumentNullThrowHelper.ThrowIfNull(tokenProvider);
    
        if (!_tokenProviders.TryGetValue(tokenProvider, out var provider))
        {
            throw new NotSupportedException(Resources.FormatNoTokenProvider(nameof(TUser), tokenProvider));
        }
        // Make sure the token is valid
        var result = await provider.ValidateAsync(purpose, token, this, user).ConfigureAwait(false);
    
        if (!result && Logger.IsEnabled(LogLevel.Debug))
        {
            Logger.LogDebug(LoggerEventIds.VerifyUserTokenFailed, "VerifyUserTokenAsync() failed with purpose: {purpose} for user.", purpose);
        }
        return result;
    }
    
  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    hi

    The EmailTokenProvider implementation is TotpSecurityStampBasedTokenProvider by default.

    It uses a fixed TimeSpan.FromMinutes(3) value.

    see https://github.com/dotnet/aspnetcore/issues/27088

    Thanks.

  • User Avatar
    0
    consultant.ahmet.ulusoy created

    Hi ma,

    Thank you for help, i implemented the token providers as needed.

    Now, everything works as i expected.

    Thank you again (l)

  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    Great : )

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 October 02, 2025, 08:00