Modern applications increasingly move away from traditional passwords and toward passwordless authentication methods that are both more secure and easier for users. In this post, I’ll show how to authenticate users in an AI-generated ASP.NET Core application using FoxIDs with OpenID Connect and enable a fully passwordless sign-in experience using one-time codes delivered via email.
We’ll start from a clean FoxIDs environment, create a new ASP.NET Core web app, connect it with OpenID Connect, and finally enable passwordless login with email-based OTP.
Creating a FoxIDs Dev Environment
I began by creating a new empty dev environment in FoxIDs. A clean environment makes it simple to set up authentication from scratch and ensures you can replicate these steps in your own tenant.
If you haven’t used FoxIDs before, you can create a free tenant at:
Each tenant comes with two ready-to-use environments so you can experiment freely.
Configure Authentication
Start by configuring how users should sign in. In this case, we want users to log in without a password, using only their email address and a one-time password (OTP) sent to them.
- Select the Authentications tab in your FoxIDs environment.
- Click Default — User Login UI.
- In the Authentication section, disable Password authentication and enable Passwordless with email (one-time password).
- Click Update to save the changes.
This enables users to create a new account and provides a passwordless experience where they authenticate simply by entering their email address and the OTP they receive.
Generate the ASP.NET Core Application
Next, we need an application to authenticate. You can use either the AI prompt to generate a new ASP.NET Core Razor Pages application targeting .NET 10 or add OpenID Connect to an existing application.
Read the “Passwordless Authentication in ASP.NET Core with FoxIDs and Email-Based OTP” post if you want to create the ASP.NET Core application by hand.
For this walkthrough, I’m generating a simple ASP.NET Core application in VS Code with Codex. You could also use Copilot.
You are an expert ASP.NET Core developer.
Goal: Create (or update) an ASP.NET Core web app that authenticates users with FoxIDs using OpenID Connect (authorization code flow), using cookie auth for the local session and OIDC as the challenge scheme.
### Mode (choose one)
- MODE = "NEW_APP" -> create a new Razor Pages app
- MODE = "EXISTING_APP" -> modify the current solution without breaking existing routes/pages
MODE: {{MODE}}
### App details
- ProjectName: {{PROJECT_NAME}} (used only if MODE = "NEW_APP")
- TargetFramework: net10.0 (or keep existing if newer)
- Local HTTPS URL (must match FoxIDs Redirect URI base address): {{APP_BASE_URL}} (example: https://localhost:7283/)
### FoxIDs OIDC configuration
Do not hard code Authority, ClientId or ClientSecret in the code or in this prompt.
Instead:
- Read them from configuration keys:
- "IdentitySettings:Authority"
- "IdentitySettings:ClientId"
- "IdentitySettings:ClientSecret"
- The final answer must clearly explain to the user where and how to set these configuration values (for example in appsettings.json, environment variables, or user–secrets).
### Implementation requirements
1) Add authentication in Program.cs:
- Configure authentication:
- DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme
- DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme
- Add cookie authentication.
- Add OpenID Connect authentication:
- Authority from config: "IdentitySettings:Authority"
- ClientId from config: "IdentitySettings:ClientId"
- ClientSecret from config: "IdentitySettings:ClientSecret"
- ResponseType = "code"
- SaveTokens = true
- Scopes: "openid", "profile", "email", "offline_access"
- MapInboundClaims = false
- TokenValidationParameters:
- NameClaimType = "sub"
- RoleClaimType = "role"
- Add OpenIdConnectEvents with:
- OnAuthenticationFailed: only in Development, return a simple plain–text response with the exception message for debugging. Never expose exception details or PII in production.
- Ensure the middleware is registered:
- app.UseAuthentication() is called before app.UseAuthorization().
2) Add configuration wiring:
- Add an `IdentitySettings` section in appsettings.json containing only non-secret placeholder values, for example:
- "Authority": "https://your-foxids-authority/"
- "ClientId": "your-client-id"
- Read "IdentitySettings:ClientSecret" from configuration, but store its value in .NET user-secrets for local development or an environment variable or secure secret store in production.
- If MODE = "EXISTING_APP", merge this section into existing configuration without overwriting unrelated settings.
- Add comments or explanatory text in the final answer that:
- These values must be replaced by the user with their real FoxIDs Authority, ClientId and ClientSecret.
- Secrets must not be written to appsettings.json or committed to source control.
3) Add login/logout endpoints:
- Create `Controllers/AuthController.cs` with a standard MVC controller:
- Use route pattern `[controller]/[action]`.
- Login action (GET):
- If the user is already authenticated, redirect to "/".
- Otherwise, issue a Challenge using the OpenIdConnectDefaults.AuthenticationScheme with RedirectUri = "/".
- Logout action (POST, with [ValidateAntiForgeryToken]):
- If the user is not authenticated, redirect to "/".
- Otherwise, SignOut from:
- CookieAuthenticationDefaults.AuthenticationScheme, and
- OpenIdConnectDefaults.AuthenticationScheme
with a RedirectUri = "/".
4) Add UI login partial:
- Create `Pages/Shared/_LoginPartial.cshtml`.
- Behaviour:
- If the user is authenticated:
- Show a "Log off" button that posts to `Auth/Logout` with an antiforgery token.
- If the user is not authenticated:
- Show a "Log in" link pointing to `Auth/Login`.
5) Add partial to layout:
- Update `Pages/Shared/_Layout.cshtml` to include:
- `<partial name="_LoginPartial" />` in the navigation bar area, preferably aligned to the right side of the navbar.
- Do not remove existing layout content.
6) Home page behaviour (for claims display):
- If MODE = "NEW_APP", or if the existing home page is effectively empty (only boilerplate or no meaningful content):
- Implement a simple home page that:
- Welcomes the user.
- If the user is authenticated, displays a list or table of the user claims (type and value).
- If the user is not authenticated, shows a message like "You are not signed in" and a hint to click the login link.
- If MODE = "EXISTING_APP" and the home page already has meaningful content:
- Do not modify the existing home page to add claims display.
- Leave the existing home page content intact.
### Output expectations
1) Code and file changes:
- List all files created or modified.
- For each file, output the complete file contents (or a very clear diff if the file is large).
- Ensure the project can build and run with `dotnet run` (or the customary command for the chosen target framework).
2) Configuration placement and guidance:
- Clearly show exactly where the Authority, ClientId and ClientSecret configuration values are read in the code (IdentitySettings section).
- Explain to the user:
- That they must set these values after the code is generated.
- How to set Authority and ClientId in appsettings.json.
- How to set ClientSecret in user-secrets locally or an environment variable or secure secret store in production.
3) Application endpoint info:
- In your final response to the user, explicitly state:
- The local endpoint URL that the application listens on (for example: `{{APP_BASE_URL}}` or the URL that the template uses).
- A short, clear instruction telling the user:
- “Configure your FoxIDs Authority and ClientId in the IdentitySettings section. Store ClientSecret in user-secrets locally or in an environment variable or secure secret store in production, so it can be read at runtime without being committed.”
4) Guardrails:
- Do not introduce unrelated refactoring.
- Do not remove any existing features beyond what is strictly required to integrate OIDC with FoxIDs.
- Keep the solution focused on:
- Adding cookie + OIDC authentication,
- AuthController,
- Login partial,
- Minimal home page changes as described.
Now implement all of the above.
The AI response should instruct you where to configure the Authority, Client ID, and Client Secret.
Now try running the application to find the endpoint.
My sample application runs locally on https://localhost:7154/
You can find the AI-generated sample code in: https://github.com/ITfoxtec/dotnet.samples/tree/main/WebAppPasswordLessEmailAI
Configure the web application in FoxIDs
Now that we know the web application’s local address, we can register it in FoxIDs so it can authenticate users through OpenID Connect.
- Select the Applications tab in your FoxIDs environment.
- Choose New application, then select Web application — OpenID Connect.
- In the Name, enter a name, for example: ASP.NET web application.
- In the Redirect URI, add the application’s base address: https://localhost:7154/ By default, FoxIDs allows redirecting to any subsequent page under this base URL. If you prefer stricter validation, you can require absolute redirect URIs.
- Click Create.
FoxIDs now displays the connection details for your new application, including:
- Authority
- Client ID
- Client Secret
Copy the Authority and Client ID into the project’s IdentitySettings section. Store the Client Secret in .NET user-secrets locally or in a secure environment variable or secret store in production.
Configure authentication in the ASP.NET application
With the FoxIDs application created, the next step is to configure authentication in the ASP.NET Core project.
Add the non-secret FoxIDs connection details to appsettings.json:
{
"IdentitySettings": {
"Authority": "https://foxids.com/{tenant}/{environment}/{application}/",
"ClientId": "your-client-id"
},
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*"
}
Store the client secret locally without adding it to appsettings.json:
dotnet user-secrets init
dotnet user-secrets set "IdentitySettings:ClientSecret" "your-client-secret"
Replace the example values with those from your own FoxIDs environment, and never commit the real client secret.
Log in
Click Log in and you are redirected to the FoxIDs login screen.
Select Create user.
Fill out the Create user form with your email (or a test email you have access to), given name, and family name, then click Create.
Enter the one-time password (OTP) you received by email, then click Log in.
You are logged in and your test user’s claims are displayed.
Next, try logging off and signing in again to experience the passwordless login flow using email OTP.