Skip to content

Implement OIDC authentication flow with automatic token management#453

Merged
StuartFerguson merged 12 commits into
mainfrom
copilot/implement-oidc-authentication-flow
Jan 4, 2026
Merged

Implement OIDC authentication flow with automatic token management#453
StuartFerguson merged 12 commits into
mainfrom
copilot/implement-oidc-authentication-flow

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Jan 4, 2026

OIDC Authentication Flow Implementation - COMPLETE ✅

Based on the old EstateManagementUI app, successfully implemented OIDC authentication for the BlazorServer project:

Implementation Complete ✅

  • Explored old EstateManagementUI project for OIDC reference
  • Created TokenManagement infrastructure (5 classes)
  • Updated Program.cs with automatic token management
  • Added /login endpoint (triggers OIDC flow)
  • Added /logout endpoint (signs out from OIDC + cookies)
  • Configured all OIDC scopes from old app
  • Updated appsettings.json with complete configuration
  • Build verification - successful (warnings only)
  • Created comprehensive documentation (OIDC_IMPLEMENTATION.md)
  • Code review and improvements applied
  • Fixed redirect_uri error by adding CallbackPath configuration
  • Added hosting.json to configure app on port 5004
  • Removed Estate Management, Merchant Management, and File Processing panels from dashboard
  • Added user profile dropdown with Sign Out option in top right corner
  • Fixed dropdown not appearing by adding proper event handling
  • Fixed rendermode error by creating separate interactive component for dropdown
  • Added prompt=login parameter to force credential re-entry after logout

Key Features Implemented

  • Hybrid Flow - Uses "code id_token" response type
  • Automatic Token Refresh - Refreshes 30 seconds before expiration
  • Token Revocation - Revokes refresh tokens on logout
  • Custom Scopes - fileProcessor, transactionProcessor
  • Claims Mapping - Standard name and role claims
  • Thread-Safe - Prevents concurrent refresh requests
  • Error Handling - Graceful handling of missing revocation endpoint
  • Callback Path - Properly configured for OIDC redirect
  • Port Configuration - App hosted on port 5004 via hosting.json
  • Clean Dashboard - Streamlined home page with statistics and quick links only
  • User Profile Dropdown - Fully functional interactive dropdown as separate component
  • Forced Re-authentication - prompt=login ensures credentials are always requested on login

Configuration

Authority: https://localhost:5001
ClientId: estateUIClient
ClientSecret: Secret1
CallbackPath: /signin-oidc
Port: 5004 (via hosting.json)
Scopes: openid, profile, email, offline_access, fileProcessor, transactionProcessor

UI Features

  • User profile dropdown in top right corner of main layout
  • Displays user name and role (Administrator)
  • Clickable avatar with animated dropdown chevron
  • Dropdown menu includes:
    • User information header
    • Sign Out link with icon (navigates to /logout endpoint)
  • Professional styling with hover effects and transitions
  • Proper event handling with stopPropagation to prevent bubbling
  • Separate interactive component (UserProfileDropdown) to avoid RenderFragment serialization issues

Authentication Flow

  • Login endpoint includes prompt=login parameter to force credential re-entry
  • OnRedirectToIdentityProvider event handler passes prompt parameter to OIDC protocol message
  • Prevents automatic re-authentication using cached credentials after logout
  • Ensures proper security by requiring users to enter credentials on each login

Issues Resolved

  • Fixed "Invalid redirect_uri" error by explicitly setting CallbackPath in OpenIdConnect options
  • Configured app to run on port 5004 for OIDC compatibility
  • Removed redundant management panels from dashboard per user feedback
  • Added logout functionality with dropdown menu in top right corner
  • Fixed dropdown not showing by adding @onclick:stopPropagation and proper button event handling
  • Fixed "Cannot pass the parameter 'Body' to component with rendermode" error by creating UserProfileDropdown as separate interactive component
  • Fixed automatic re-authentication issue by adding prompt=login parameter

Ready for Testing

User can now test:

  • Login flow with actual OIDC provider (app running on port 5004)
  • User profile dropdown in top right corner (now fully functional)
  • Logout functionality via dropdown Sign Out link
  • Re-login requires credential entry (no automatic re-authentication)
  • Automatic token refresh
  • Access to protected resources with proper scopes
Original prompt

This section details on the original issue you should resolve

<issue_title>OIDC Authentication Flow</issue_title>
<issue_description>I would like you to implement the oidc authentication flow in my application.

If you refer to the old EstateManagementUI app all the information to configure this is in there.

I do realise however you cannot test this for me to I cna do the testing side of things if you get all the code configured.</issue_description>

Comments on the Issue (you are @copilot in this section)


💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

Copilot AI and others added 3 commits January 4, 2026 08:03
Co-authored-by: StuartFerguson <16325469+StuartFerguson@users.noreply.github.com>
Co-authored-by: StuartFerguson <16325469+StuartFerguson@users.noreply.github.com>
Co-authored-by: StuartFerguson <16325469+StuartFerguson@users.noreply.github.com>
Copilot AI changed the title [WIP] Implement OIDC authentication flow in application Implement OIDC authentication flow with automatic token management Jan 4, 2026
Copilot AI requested a review from StuartFerguson January 4, 2026 08:09
@StuartFerguson
Copy link
Copy Markdown
Member

@copilot i get this error
Microsoft.IdentityModel.Protocols.OpenIdConnect.OpenIdConnectProtocolException: Message contains error: 'invalid_request', error_description: 'Invalid redirect_uri', error_uri: 'error_uri is null'.

Co-authored-by: StuartFerguson <16325469+StuartFerguson@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented Jan 4, 2026

@copilot i get this error
Microsoft.IdentityModel.Protocols.OpenIdConnect.OpenIdConnectProtocolException: Message contains error: 'invalid_request', error_description: 'Invalid redirect_uri', error_...

Fixed in commit 96fbb9e. The issue was that the CallbackPath wasn't explicitly set in the OpenIdConnect options. I've added:

options.CallbackPath = builder.Configuration["Authentication:CallbackPath"] ?? "/signin-oidc";

This ensures the redirect URI is properly configured as /signin-oidc. Make sure this callback URL is registered in your OIDC provider's client configuration.

@StuartFerguson
Copy link
Copy Markdown
Member

@copilot can you add in a hosting.json file and host the app on port 5004, thats causing my oidc to fail

Co-authored-by: StuartFerguson <16325469+StuartFerguson@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented Jan 4, 2026

@copilot can you add in a hosting.json file and host the app on port 5004, thats causing my oidc to fail

Added in commit 2fa1ab6. Created hosting.json with port 5004 configuration and updated Program.cs to load it:

{
  "urls": "https://*:5004"
}

The app will now run on port 5004. Make sure your OIDC provider's redirect URI is configured to use port 5004 (e.g., https://localhost:5004/signin-oidc).

@StuartFerguson
Copy link
Copy Markdown
Member

@copilot ok great that works now, can you remove the pannels below from the logged in dashboard

image

@StuartFerguson
Copy link
Copy Markdown
Member

@copilot, I also need a way to log out probably using this in the top right corner with a signout drop down ?

image

…nels from dashboard

Co-authored-by: StuartFerguson <16325469+StuartFerguson@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented Jan 4, 2026

@copilot ok great that works now, can you remove the pannels below from the logged in dashboard

<img width="1629" height="387" alt="image" src="https://github.com/user-attachments/assets/0ebc1d15-b...

Removed in commit 92db629. The three panels (Estate Management, Merchant Management, and File Processing) have been removed from the dashboard.

The dashboard now shows:

  • Info boxes at the top (Total Estates, Total Merchants, Total Contracts, Total Operators)
  • Quick Links section (Contract Management, Operator Management)
  • System Status section (showing active services)

The three large panels with feature lists and "View Estate", "View Merchants", and "View Files" buttons have been removed as requested.

Co-authored-by: StuartFerguson <16325469+StuartFerguson@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented Jan 4, 2026

@copilot, I also need a way to log out probably using this in the top right corner with a signout drop down ?

<img width="251" height="75" alt="image" src="https://github.com/user-attachments/asset...

Added in commit 120185c. The user profile section in the top right corner now includes a dropdown menu with a "Sign Out" option.

Features added:

  • Clickable user avatar with dropdown chevron icon that rotates when opened
  • Dropdown menu showing:
    • User name and role (Administrator)
    • Sign Out link with icon (navigates to /logout)
  • Professional styling with hover effects and smooth transitions
  • The dropdown displays below the user avatar on the right side

When clicked, the "Sign Out" option will navigate to the /logout endpoint which signs out from both OIDC and local cookies.

@StuartFerguson
Copy link
Copy Markdown
Member

@copilot the dropdown for logout doesnt show when i click on the button at the top right

…pagation

Co-authored-by: StuartFerguson <16325469+StuartFerguson@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented Jan 4, 2026

@copilot the dropdown for logout doesnt show when i click on the button at the top right

Fixed in commit 8179996. The issue was that the @onclick event wasn't properly attached to the button element. I've made the following changes:

  1. Moved the @onclick="ToggleDropdown" from the div to the actual button element
  2. Added type="button" to the button to prevent form submission
  3. Added @onclick:stopPropagation to both the button and dropdown to prevent event bubbling

The dropdown should now appear when you click on the user avatar in the top right corner. Click it again or click outside to close it.

@StuartFerguson
Copy link
Copy Markdown
Member

@copilot still nothing when I click on this

image

…eractivity

Co-authored-by: StuartFerguson <16325469+StuartFerguson@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented Jan 4, 2026

@copilot still nothing when I click on this

image

...

Fixed in commit 3a25b91. The issue was that the MainLayout component needed the @rendermode InteractiveServer directive to enable server-side interactivity in Blazor Server.

I've added:

@rendermode InteractiveServer

This directive is required in .NET 10 Blazor Server for components that use interactive features like @onclick event handlers. Without it, the component renders as static HTML and the dropdown toggle won't work.

The dropdown should now appear when you click on the user avatar with the "ES" initials in the top right corner.

@StuartFerguson
Copy link
Copy Markdown
Member

@copilot i get this error now

An unhandled exception occurred while processing the request.
InvalidOperationException: Cannot pass the parameter 'Body' to component 'MainLayout' with rendermode 'InteractiveServerRenderMode'. This is because the parameter is of the delegate type 'Microsoft.AspNetCore.Components.RenderFragment', which is arbitrary code and cannot be serialized.
Microsoft.AspNetCore.Components.Endpoints.SSRRenderModeBoundary.ValidateParameters(IReadOnlyDictionary<string, object> latestParameters)

…nent

Co-authored-by: StuartFerguson <16325469+StuartFerguson@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented Jan 4, 2026

@copilot i get this error now

An unhandled exception occurred while processing the request.
...

Fixed in commit eda45bb. The error occurred because in .NET 10 Blazor, layout components that receive RenderFragment parameters (like Body) cannot use @rendermode InteractiveServer due to serialization limitations.

Solution implemented:

  1. Removed @rendermode InteractiveServer from MainLayout.razor
  2. Created a new separate component: UserProfileDropdown.razor with @rendermode InteractiveServer
  3. This component handles all the interactive dropdown functionality independently
  4. MainLayout now uses <UserProfileDropdown UserName="@context.User.Identity?.Name" /> to embed the interactive component

This approach follows the recommended pattern: keep layouts static and make only specific child components interactive when needed. The dropdown should now work without the serialization error.

@StuartFerguson
Copy link
Copy Markdown
Member

@copilot ok the signout link now works however I have noticed a small issue that when i click signout, followed by sign in I am not prompted again for crededntials to log in

Co-authored-by: StuartFerguson <16325469+StuartFerguson@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented Jan 4, 2026

@copilot ok the signout link now works however I have noticed a small issue that when i click signout, followed by sign in I am not prompted again for crededntials to log in

Fixed in commit 2f7c55a. The issue was that the OIDC provider was maintaining an active session, so when you clicked "Sign In" after logging out, it automatically re-authenticated without prompting for credentials.

Changes made:

  1. Added prompt=login parameter to the /login endpoint authentication properties
  2. Added OnRedirectToIdentityProvider event handler in OpenIdConnect configuration to pass the prompt parameter to the OIDC protocol message

This forces the OIDC provider to always prompt for credentials on the login page, even if a session exists. Now when you sign out and then sign in again, you'll be required to enter your credentials.

@StuartFerguson StuartFerguson marked this pull request as ready for review January 4, 2026 12:42
@StuartFerguson StuartFerguson merged commit e0c102b into main Jan 4, 2026
5 checks passed
@github-actions github-actions Bot deleted the copilot/implement-oidc-authentication-flow branch March 6, 2026 01:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

OIDC Authentication Flow

2 participants