Skip to content

Instantly share code, notes, and snippets.

@doriandres
Last active March 17, 2024 06:56
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save doriandres/e3df57e1cd9a3498e797a566df2a940b to your computer and use it in GitHub Desktop.
Save doriandres/e3df57e1cd9a3498e797a566df2a940b to your computer and use it in GitHub Desktop.
Sign in users with a C# .NET 8 Application and LinkedIn OpenID Connect
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authentication.OpenIdConnect;
using Microsoft.IdentityModel.Protocols.OpenIdConnect;
using System.Security.Claims;
namespace MyApp;
public class Program
{
public static void Main(string[] args)
{
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddLinkedInAuthentication(new ()
{
// create an app at https://developer.linkedin.com to obtain these values
ClientId = "<CLIENT_ID>",
ClientSecret = "<CLIENT_SECRET>",
RedirectUrl = "/oauth/linkedin/redirect", // define at oauth 2.0 settings in app settings
});
builder.Services.AddAuthorization();
var app = builder.Build();
app.UseHttpsRedirection();
app.UseCookiePolicy();
app.UseAuthentication();
app.UseAuthorization();
app.MapGet("/", async (HttpContext context) =>
{
var profile = context.User.GetLinkedInProfile(); // get user profile
context.Response.Headers.ContentType = "text/html";
await context.Response.WriteAsync($"""
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>LinkedIn Sign In Demo</title>
</head>
<body>
<h1>Hello {profile.Name}!</h1>
</body>
</html>
""");
}).RequireAuthorization(); // make sure your route is protected
app.Run();
}
}
public static class LinkedInAuthExtensions
{
public static LinkedInAuthenticationProfile GetLinkedInProfile(this ClaimsPrincipal user) => new(user);
public static AuthenticationBuilder AddLinkedInAuthentication(this IServiceCollection services, LinkedInAuthenticationConfig config)
{
return services.AddAuthentication(o =>
{
o.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
o.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
})
.AddCookie()
.AddOpenIdConnect(o =>
{
o.ResponseType = OpenIdConnectResponseType.Code;
o.Authority = "https://www.linkedin.com/oauth/";
o.ClientId = config.ClientId;
o.ClientSecret = config.ClientSecret;
o.CallbackPath = config.RedirectUrl;
o.SaveTokens = true;
o.GetClaimsFromUserInfoEndpoint = true;
o.ProtocolValidator = new () { RequireNonce = false, RequireState = false };
o.Events = new OpenIdConnectEvents
{
OnAuthorizationCodeReceived = (ctx) =>
{
ctx.TokenEndpointRequest = new OpenIdConnectMessage
{
GrantType = "authorization_code",
Code = ctx.Request.Query["code"],
RedirectUri = $"{ctx.Request.Scheme}://{ctx.Request.Host}{config.RedirectUrl}",
ClientId = config.ClientId,
ClientSecret = config.ClientSecret,
};
return Task.CompletedTask;
}
};
});
}
}
public class LinkedInAuthenticationConfig
{
public string ClientId { get; set; } = "";
public string ClientSecret { get; set; } = "";
public string RedirectUrl { get; set; } = "";
}
public class LinkedInAuthenticationProfile(ClaimsPrincipal user)
{
public string? Name => user.Claims.FirstOrDefault(c => c.Type == "name")?.Value;
// Add other fields as needed, just read them from the claims object
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment