Search code examples
c#asp.net-mvcasp.net-identityopenid-connectowin

How to persist additional claims and tokens from external providers in ASP.NET MVC 5


I have an app that is written on the top of an old ASP.NET MVC 5 framework using C#. I want to enable OpenIdConnect authentication to allow my users to authenticate using a private OpenId server.

I was able to add the OpenId external provider using Microsoft.Owin.Security.OpenIdConnect project. Here is how configured the OpenId authentication provider

app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions()
{
    Authority = "openid-server-domain.com",
    RedeemCode = true,
    SaveTokens = true,
    ResponseType = "code",
    ClientId = "***",
    ClientSecret = "***",
    RedirectUri = "https://localhost:55555/connect/redirect",
    PostLogoutRedirectUri = "/disconnect/sign-out",
    Scope = "openid profile email"
});

As you can see above, I am requesting access to the profile and email scopes which should give me info like username, email and some others. I want to add the data sent by the OpenId server as claims to the user.

Question How to persist additional claims and tokens from external providers in ASP.NET MVC 5?


Solution

  • I managed to get it to work by subscribing to the SecurityTokenValidated event and call the userinfo API on the server. I am not sure if this is the best approach.

    
                app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions()
                {
                    Authority = "openid-server-domain.com",
                    RedeemCode = true,
                    SaveTokens = true,
                    ResponseType = "code",
                    ClientId = "***",
                    ClientSecret = "***",
                    RedirectUri = "https://localhost:55555/connect/redirect",
                    PostLogoutRedirectUri = "/disconnect/sign-out",
                    Scope = "openid profile email"
                    Notifications = new OpenIdConnectAuthenticationNotifications()
                    {
                        SecurityTokenValidated = async context =>
                        {
                            var id = context.AuthenticationTicket.Identity;
    
                            var client = new HttpClient()
                            {
                                BaseAddress = new Uri("openid-server-domain.com"),
                            };
    
                            client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
                            client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", context.ProtocolMessage.AccessToken);
    
                            var response = await client.GetAsync("connect/userinfo");
    
                            if (response.IsSuccessStatusCode)
                            {
                                var data = await response.Content.ReadAsStringAsync();
    
                                var info = JsonConvert.DeserializeObject<OpenIdUserInfo>(data);
    
                                if(!String.IsNullOrWhiteSpace(info.Name))
                                {
                                    id.AddClaim(new Claim("name", info.Name));
                                }
                            }
    
                            context.AuthenticationTicket = new AuthenticationTicket(id, context.AuthenticationTicket.Properties);
                        }
                    }
                });