I'm trying to implement LinkedIn Sign In OAuth 2 with Blazor Server Side.
But I have a problem.
When I declare the authorized redirect URLs for my app as "https://localhost:7167/signin-linkedin" I got an error "The redirect_uri does not match the registered value"
I checked the redirect_uri value in the URI parameter, it's "https://localhost:7167/login/signin-linkedin"
I added this URI as authorized redirect URLs, the login works fine now, but just after the sign-in, there is a cyclic redirect. And the browser throws an error "too many redirections"
program.cs
builder.Services.AddAuthentication(options =>
{
options.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
})
.AddCookie(o =>
{
o.LoginPath = new PathString("/login");
o.LogoutPath = new PathString("/logout");
})
.AddOAuth("LinkedIn", options =>
{
options.ClientId = "sampletest";
options.ClientSecret = "sampletest";
options.ClaimsIssuer = LinkedInAuthenticationDefaults.Issuer;
options.CallbackPath = new PathString("/signin-linkedin"); //LinkedInAuthenticationDefaults.CallbackPath;
options.AuthorizationEndpoint = LinkedInAuthenticationDefaults.AuthorizationEndpoint;
options.TokenEndpoint = LinkedInAuthenticationDefaults.TokenEndpoint;
options.UserInformationEndpoint = LinkedInAuthenticationDefaults.UserInformationEndpoint;
options.Scope.Add("r_liteprofile");
options.Scope.Add("r_emailaddress");
options.Events = new OAuthEvents
{
OnCreatingTicket = async context =>
{
var request = new HttpRequestMessage(HttpMethod.Get, context.Options.UserInformationEndpoint);
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", context.AccessToken);
request.Headers.Add("x-li-format", "json");
var response = await context.Backchannel.SendAsync(request, context.HttpContext.RequestAborted);
response.EnsureSuccessStatusCode();
var user = JObject.Parse(await response.Content.ReadAsStringAsync());
var userId = user.Value<string>("id");
if (!string.IsNullOrEmpty(userId))
context.Identity?.AddClaim(new Claim(ClaimTypes.NameIdentifier, userId, ClaimValueTypes.String,
context.Options.ClaimsIssuer));
var formattedName = user.Value<string>("formattedName");
if (!string.IsNullOrEmpty(formattedName))
context.Identity?.AddClaim(new Claim(ClaimTypes.Name, formattedName, ClaimValueTypes.String,
context.Options.ClaimsIssuer));
var email = user.Value<string>("emailAddress");
if (!string.IsNullOrEmpty(email))
context.Identity?.AddClaim(new Claim(ClaimTypes.Email, email, ClaimValueTypes.String,
context.Options.ClaimsIssuer));
var pictureUrl = user.Value<string>("pictureUrl");
if (!string.IsNullOrEmpty(email))
context.Identity?.AddClaim(new Claim("profile-picture", pictureUrl, ClaimValueTypes.String,
context.Options.ClaimsIssuer));
}
};
});
app.Map("/login", applicationBuilder =>
{
applicationBuilder.Run(async context =>
{
await context.ChallengeAsync("LinkedIn",
properties: new AuthenticationProperties { RedirectUri = "/" });
});
});
app.Map("/logout", applicationBuilder =>
{
applicationBuilder.Run(async context =>
{
await context.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
context.Response.Redirect("/");
});
});
Ok, there is a weird behavior with Blazor routing. Blazor add the callback path to the current path. There is nothing to do.
I just add a controller with routing, and it works. The callback path is added to base uri.