Skip to content

Commit 2e0a2f0

Browse files
committed
Enable GitHub OAuth
1 parent 2851778 commit 2e0a2f0

File tree

7 files changed

+123
-2
lines changed

7 files changed

+123
-2
lines changed

HelloGithubOAuth.csproj

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,15 @@
1-
<Project Sdk="Microsoft.NET.Sdk.Web">
1+
<Project Sdk="Microsoft.NET.Sdk.Web">
22

33
<PropertyGroup>
44
<TargetFramework>net7.0</TargetFramework>
55
<Nullable>enable</Nullable>
66
<ImplicitUsings>enable</ImplicitUsings>
7+
<UserSecretsId>63c704c5-1b97-410e-8252-657094113e9a</UserSecretsId>
78
</PropertyGroup>
89

10+
<ItemGroup>
11+
<PackageReference Include="AspNet.Security.OAuth.GitHub" Version="7.0.0" />
12+
<PackageReference Include="Octokit" Version="5.0.0" />
13+
</ItemGroup>
14+
915
</Project>

Pages/Index.cshtml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,5 @@
66

77
<div class="text-center">
88
<h1 class="display-4">Welcome</h1>
9-
<p>Learn about <a href="https://docs.microsoft.com/aspnet/core">building Web apps with ASP.NET Core</a>.</p>
9+
<p>Learn <a asp-area="" asp-page="/Secret">my secret</a>.</p>
1010
</div>

Pages/Secret.cshtml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,10 @@
11
@page
22
@model HelloGithubOAuth.Pages.SecretModel
33
@{
4+
ViewData["Title"] = "Top Secret";
45
}
6+
7+
<div class="text-center">
8+
<h1 class="display-4">🧁 I ate <em>two</em> cakes! 🧁</h1>
9+
[<a href="/Signout">sign out</a>]
10+
</div>

Pages/Secret.cshtml.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1+
using Microsoft.AspNetCore.Authorization;
12
using Microsoft.AspNetCore.Mvc;
23
using Microsoft.AspNetCore.Mvc.RazorPages;
34

45
namespace HelloGithubOAuth.Pages
56
{
7+
[Authorize]
68
public class SecretModel : PageModel
79
{
810
public void OnGet()

Pages/Signin.cshtml

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,29 @@
11
@page
2+
3+
@*
4+
// Based on code by Khalid Abuhakmeh:
5+
// https://khalidabuhakmeh.com/github-openid-auth-aspnet-core-apps
6+
*@
7+
28
@model HelloGithubOAuth.Pages.SigninModel
39
@{
10+
ViewData["Title"] = "Signin Page";
411
}
12+
13+
<div class="jumbotron">
14+
<h1>Authentication</h1>
15+
<p class="lead text-left">Sign in using one of these external providers:</p>
16+
17+
@foreach (var scheme in Model.Schemes!.OrderBy(p => p.DisplayName));
18+
@foreach (var scheme in Model.Schemes!)
19+
{
20+
<form asp-page="SignIn" method="post">
21+
<input type="hidden" name="Provider" value="@scheme.Name" />
22+
<input type="hidden" name="ReturnUrl" value="@Model.ReturnUrl" />
23+
24+
<button class="btn btn-lg btn-success m-1" type="submit">
25+
Sign in using @scheme.DisplayName
26+
</button>
27+
</form>
28+
}
29+
</div>

Pages/Signin.cshtml.cs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,49 @@
1+
// Based on code by Khalid Abuhakmeh:
2+
// https://khalidabuhakmeh.com/github-openid-auth-aspnet-core-apps
3+
4+
using Microsoft.AspNetCore.Authentication;
15
using Microsoft.AspNetCore.Mvc;
26
using Microsoft.AspNetCore.Mvc.RazorPages;
37

48
namespace HelloGithubOAuth.Pages
59
{
610
public class SigninModel : PageModel
711
{
12+
public IEnumerable<AuthenticationScheme>? Schemes { get; set; }
13+
14+
[BindProperty(SupportsGet = true)]
15+
public string? ReturnUrl { get; set; }
816
public void OnGet()
917
{
18+
Schemes = GetExternalProvidersAsync(HttpContext);
19+
}
20+
21+
public IActionResult OnPost([FromForm] string provider)
22+
{
23+
if (string.IsNullOrWhiteSpace(provider))
24+
{
25+
return BadRequest();
26+
}
27+
28+
return IsProviderSupportedAsync(HttpContext, provider) is false
29+
? BadRequest()
30+
: Challenge(new AuthenticationProperties
31+
{
32+
RedirectUri = Url.IsLocalUrl(ReturnUrl) ? ReturnUrl : "/"
33+
}, provider);
1034
}
35+
36+
private static AuthenticationScheme[] GetExternalProvidersAsync(HttpContext context)
37+
{
38+
var schemes = context.RequestServices.GetRequiredService<IAuthenticationSchemeProvider>();
39+
return (schemes.GetAllSchemesAsync())
40+
.Result
41+
.Where(scheme => !string.IsNullOrEmpty(scheme.DisplayName))
42+
.ToArray();
43+
}
44+
45+
private static bool IsProviderSupportedAsync(HttpContext context, string provider) =>
46+
GetExternalProvidersAsync(context)
47+
.Any(scheme => string.Equals(scheme.Name, provider, StringComparison.OrdinalIgnoreCase));
1148
}
1249
}

Program.cs

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,55 @@
1+
// Authentication based on code by Khalid Abuhakmeh:
2+
// https://khalidabuhakmeh.com/github-openid-auth-aspnet-core-apps
3+
4+
using System.Security.Claims;
5+
using Microsoft.AspNetCore.Authentication.Cookies;
6+
using Microsoft.AspNetCore.Authentication;
7+
18
var builder = WebApplication.CreateBuilder(args);
29

310
// Add services to the container.
411
builder.Services.AddRazorPages();
512

13+
builder.Services.AddAuthentication(o =>
14+
{
15+
o.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
16+
})
17+
.AddCookie(o =>
18+
{
19+
o.LoginPath = "/signin";
20+
o.LogoutPath = "/signout";
21+
})
22+
.AddGitHub(opts =>
23+
{
24+
opts.ClientId = builder.Configuration["github:clientId"]!;
25+
opts.ClientSecret = builder.Configuration["github:clientSecret"]!;
26+
opts.CallbackPath = "/signin-github";
27+
28+
opts.Events.OnCreatingTicket += context =>
29+
{
30+
if (context.AccessToken is { })
31+
{
32+
context.Identity?.AddClaim(
33+
new Claim("access_token", context.AccessToken));
34+
}
35+
return Task.CompletedTask;
36+
};
37+
});
38+
639
var app = builder.Build();
740

41+
app.UseAuthentication();
42+
app.MapGet("/signout", async ctx =>
43+
{
44+
await ctx.SignOutAsync(
45+
CookieAuthenticationDefaults.AuthenticationScheme,
46+
new AuthenticationProperties
47+
{
48+
RedirectUri = "/"
49+
});
50+
});
51+
52+
853
// Configure the HTTP request pipeline.
954
if (!app.Environment.IsDevelopment())
1055
{

0 commit comments

Comments
 (0)