Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

XS✔ ◾ Improved headings /migrate-an-existing-user-store-to-an-externalauthp… #7421

Merged
merged 1 commit into from
Dec 6, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@ guid: 38a5988b-1740-4120-840d-116ad6e91566
redirects:
- integrate-identityserver-with-an-existing-user-store
- migrate-an-existing-user-store-to-an-externalauthprovider

---

When integrating an external authentication provider (IdentityServer, Azure AD or Microsoft Entra ID etc.) with an existing ASP .NET Core application which uses ASP .NET Core Identity, challenges arise due to different user identification systems.

On the ExternalAuthProvider side, users are typically recognised by a unique SubId within their issued token after authentication. In contrast, an application's existing user store might use its own unique user ID, possibly combined with other data.
Expand All @@ -19,19 +21,19 @@ The above discrepancy creates the need to effectively map or correlate the the u

Two essential scenarios arise when integrating the ExternalAuthProvider:

## 1. Pre-existing Company Users
## 1. Pre-existing company users

Addressing users already registered with company emails in the existing application user store now authenticating through the ExternalAuthProvider:

**SubId Check**:
#### SubId check

Begin by verifying if the user has an external login associated with the SubId from the ExternalAuthProvider in your application's user store using the [`FindByLoginAsync()`](https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.identity.usermanager-1.findbyloginasync?view=aspnetcore-7.0) method. If found, proceed with authentication by handling the request gracefully.

```csharp
var existingUserByExternalLogin = await _userManager.FindByLoginAsync(EXTERNAL_AUTH_PROVIDER, subId);
```

**Existing Users by Email Verification**:
#### Existing users by email verification

If there's no associated SubId, check if the email (provided by the ExternalAuthProvider during authentication available as one of the claims in the JWT token) exists in your application's user store.

Expand All @@ -43,7 +45,7 @@ var userByUserName = await _userManager.FindByEmailAsync(emailFromIdentityServer
Figure: Retrieving existing user by using the Email claim from the JWT token utilising the FindByEmailAsync() from the UserManager class.
:::

**For users known to your application but not authenticated via the ExternalAuthProvider**:
#### Users known to the application but not authenticated via ExternalAuthProvider

Retrieve the SubId from the JWT token provided by the ExternalAuthProvider. Use ASP .NET Core Identity's [`AddLoginAsync()`](https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.identity.usermanager-1.addloginasync?view=aspnetcore-8.0) method to associate this SubId as an external login with the user's record.

Expand All @@ -56,28 +58,28 @@ await _userManager.AddLoginAsync(newUser, new UserLoginInfo(EXTERNAL_AUTH_PROVID
**Note**: In the example above the "EXTERNAL\_AUTH\_PROVIDER" is a constant which contains the identifier for your external authentication provider. e.g. IDENTITY\_SERVER\_EXTERNAL\_LOGIN = "IdentityServer"
:::

**Future Authentications**:
#### Future Authentications

For all subsequent logins, employ the [`FindAsync(new UserLoginInfo())`](https://learn.microsoft.com/en-us/previous-versions/aspnet/dn497605(v=vs.108)) method.

**Benefits**:
### ✅ Benefits

* Seamless authentication experience for existing users.
* Avoids custom fields in the ApplicationUser model, leveraging existing ASP .NET Identity Core methods like [`AddLoginAsync`](https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.identity.usermanager-1.addloginasync?view=aspnetcore-8.0) and [`FindAsync`](https://learn.microsoft.com/en-us/previous-versions/aspnet/dn497605(v=vs.108)).
* Seamless authentication experience for existing users
* Avoids custom fields in the ApplicationUser model, leveraging existing ASP .NET Identity Core methods like [`AddLoginAsync`](https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.identity.usermanager-1.addloginasync?view=aspnetcore-8.0) and [`FindAsync`](https://learn.microsoft.com/en-us/previous-versions/aspnet/dn497605(v=vs.108))

## 2. New ExternalAuthProvider Registrants
## 2. New ExternalAuthProvider registrants

Incorporating users who are new to both the ExternalAuthProvider and the application:

**Email Verification**:
#### Email verification

Check if the email provided by the ExternalAuthProvider during authentication exists in your application's user store by using ASP .NET Identity Core methods like [`FindByEmailAsync()`](https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.identity.usermanager-1.findbyemailasync?view=aspnetcore-7.0). If it doesn't, this indicates the user is new.

```csharp
var existingUser = await _userManager.FindByEmailAsync(emailFromIdentityServer);
```

**User Creation & SubId Association**:
#### User creation & SubId association

Register by creating a new user in your application's store using claims provided by the ExternalAuthProvider (e.g., first name, last name, email).

Expand Down Expand Up @@ -106,15 +108,15 @@ var subId = token.Claims.FirstOrDefault(c => c.Type == "sub");
await _userManager.AddLoginAsync(newUser, new UserLoginInfo(EXTERNAL_AUTH_PROVIDER, subId));
```

**Future Authentications**:
#### Future Authentications

Finally for all subsequent logins use the [`FindByLoginAsync()`](https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.identity.usermanager-1.findbyloginasync?view=aspnetcore-7.0) method to check if the user already exists.

```csharp
var existingUser = await _userManager.FindByLoginAsync(EXTERNAL_AUTH_PROVIDER, subId));
```

**Benefits**:
### ✅ Benefits

* Facilitates the seamless integration of new users to the ecosystem.
* Consistent user experience for new users, leveraging native ASP .NET Core Identity methods.
Expand Down
Loading