Skip to content

Commit c1b180f

Browse files
authored
feat: support identifiers, first_screen, direct_sign_in and extra_params sign-in params (#32)
1 parent f30361c commit c1b180f

File tree

5 files changed

+216
-5
lines changed

5 files changed

+216
-5
lines changed

samples/sample-blazor/Program.cs

+29-2
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,35 @@
4747
{
4848
if (!(context.User?.Identity?.IsAuthenticated ?? false))
4949
{
50-
await context.ChallengeAsync(new AuthenticationProperties { RedirectUri = "/" });
51-
} else {
50+
var authProperties = new AuthenticationProperties
51+
{
52+
RedirectUri = "/"
53+
};
54+
55+
/// <see href="https://docs.logto.io/docs/references/openid-connect/authentication-parameters/#first-screen"/>
56+
/// <see cref="LogtoParameters.Authentication.FirstScreen"/>
57+
authProperties.SetParameter("first_screen", LogtoParameters.Authentication.FirstScreen.Register);
58+
59+
// This parameter MUST be used together with `first_screen`.
60+
authProperties.SetParameter("identifiers", string.Join(",", new[]
61+
{
62+
LogtoParameters.Authentication.Identifiers.Username,
63+
}));
64+
65+
var directSignIn = new LogtoParameters.Authentication.DirectSignIn
66+
{
67+
Target = "github",
68+
Method = LogtoParameters.Authentication.DirectSignIn.Methods.Social
69+
};
70+
71+
/// <see href="https://docs.logto.io/docs/references/openid-connect/authentication-parameters/#direct-sign-in"/>
72+
/// <see cref="LogtoParameters.Authentication.DirectSignIn"/>
73+
authProperties.SetParameter("direct_sign_in", System.Text.Json.JsonSerializer.Serialize(directSignIn));
74+
75+
await context.ChallengeAsync(authProperties);
76+
}
77+
else
78+
{
5279
context.Response.Redirect("/");
5380
}
5481
});

samples/sample-mvc/Controllers/HomeController.cs

+27-1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
using Microsoft.AspNetCore.Authentication;
44
using Microsoft.AspNetCore.Mvc;
55
using sample_mvc.Models;
6+
using System.Text.Json;
67

78
namespace sample_mvc.Controllers;
89

@@ -25,7 +26,32 @@ public async Task<IActionResult> Index()
2526

2627
public IActionResult SignIn()
2728
{
28-
return Challenge(new AuthenticationProperties { RedirectUri = "/" });
29+
var authProperties = new AuthenticationProperties
30+
{
31+
RedirectUri = "/"
32+
};
33+
34+
/// <see href="https://docs.logto.io/docs/references/openid-connect/authentication-parameters/#first-screen"/>
35+
/// <see cref="LogtoParameters.Authentication.FirstScreen"/>
36+
authProperties.SetParameter("first_screen", LogtoParameters.Authentication.FirstScreen.Register);
37+
38+
// This parameter MUST be used together with `first_screen`.
39+
authProperties.SetParameter("identifiers", string.Join(",", new[]
40+
{
41+
LogtoParameters.Authentication.Identifiers.Username,
42+
}));
43+
44+
var directSignIn = new LogtoParameters.Authentication.DirectSignIn
45+
{
46+
Target = "github",
47+
Method = LogtoParameters.Authentication.DirectSignIn.Methods.Social
48+
};
49+
50+
/// <see href="https://docs.logto.io/docs/references/openid-connect/authentication-parameters/#direct-sign-in"/>
51+
/// <see cref="LogtoParameters.Authentication.DirectSignIn"/>
52+
authProperties.SetParameter("direct_sign_in", JsonSerializer.Serialize(directSignIn));
53+
54+
return Challenge(authProperties);
2955
}
3056

3157
// Use the `new` keyword to avoid conflict with the `ControllerBase.SignOut` method

samples/sample/Pages/Index.cshtml.cs

+27-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using Logto.AspNetCore.Authentication;
22
using Microsoft.AspNetCore.Authentication;
33
using Microsoft.AspNetCore.Mvc.RazorPages;
4+
using System.Text.Json;
45

56
namespace sample.Pages;
67

@@ -22,7 +23,32 @@ public async Task OnGetAsync()
2223

2324
public async Task OnPostSignInAsync()
2425
{
25-
await HttpContext.ChallengeAsync(new AuthenticationProperties { RedirectUri = "/" });
26+
var authProperties = new AuthenticationProperties
27+
{
28+
RedirectUri = "/"
29+
};
30+
31+
/// <see href="https://docs.logto.io/docs/references/openid-connect/authentication-parameters/#first-screen"/>
32+
/// <see cref="LogtoParameters.Authentication.FirstScreen"/>
33+
authProperties.SetParameter("first_screen", LogtoParameters.Authentication.FirstScreen.Register);
34+
35+
// This parameter MUST be used together with `first_screen`
36+
authProperties.SetParameter("identifiers", string.Join(",", new[]
37+
{
38+
LogtoParameters.Authentication.Identifiers.Username,
39+
}));
40+
41+
var directSignIn = new LogtoParameters.Authentication.DirectSignIn
42+
{
43+
Target = "github",
44+
Method = LogtoParameters.Authentication.DirectSignIn.Methods.Social
45+
};
46+
47+
/// <see href="https://docs.logto.io/docs/references/openid-connect/authentication-parameters/#direct-sign-in"/>
48+
/// <see cref="LogtoParameters.Authentication.DirectSignIn"/>
49+
authProperties.SetParameter("direct_sign_in", JsonSerializer.Serialize(directSignIn));
50+
51+
await HttpContext.ChallengeAsync(authProperties);
2652
}
2753

2854
public async Task OnPostSignOutAsync()

src/Logto.AspNetCore.Authentication/LogtoParameters.cs

+93
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using Microsoft.IdentityModel.Protocols.OpenIdConnect;
2+
using System.Collections.Generic;
23

34
namespace Logto.AspNetCore.Authentication;
45

@@ -115,4 +116,96 @@ public static class Claims
115116
/// </summary>
116117
public const string Identities = "identities";
117118
}
119+
120+
/// <summary>
121+
/// The authentication parameters for Logto sign-in experience customization.
122+
/// </summary>
123+
public static class Authentication
124+
{
125+
/// <summary>
126+
/// The first screen to show in the sign-in experience.
127+
/// See <see href="https://docs.logto.io/docs/references/openid-connect/authentication-parameters/#first-screen"/> for more details.
128+
/// </summary>
129+
public static class FirstScreen
130+
{
131+
/// <summary>
132+
/// Show the register form first.
133+
/// </summary>
134+
public const string Register = "identifier:register";
135+
136+
/// <summary>
137+
/// Show the sign-in form first.
138+
/// </summary>
139+
public const string SignIn = "identifier:sign_in";
140+
141+
/// <summary>
142+
/// Show the single sign-on form first.
143+
/// </summary>
144+
public const string SingleSignOn = "single_sign_on";
145+
146+
/// <summary>
147+
/// Show the reset password form first.
148+
/// </summary>
149+
public const string ResetPassword = "reset_password";
150+
}
151+
152+
/// <summary>
153+
/// The identifiers to use for authentication.
154+
/// This parameter MUST be used together with <see cref="FirstScreen"/>.
155+
/// </summary>
156+
public static class Identifiers
157+
{
158+
/// <summary>
159+
/// Use email for authentication.
160+
/// </summary>
161+
public const string Email = "email";
162+
163+
/// <summary>
164+
/// Use phone for authentication.
165+
/// </summary>
166+
public const string Phone = "phone";
167+
168+
/// <summary>
169+
/// Use username for authentication.
170+
/// </summary>
171+
public const string Username = "username";
172+
}
173+
174+
/// <summary>
175+
/// Direct sign-in configuration.
176+
/// See <see href="https://docs.logto.io/docs/references/openid-connect/authentication-parameters/#direct-sign-in"/> for more details.
177+
/// </summary>
178+
public class DirectSignIn
179+
{
180+
/// <summary>
181+
/// The target identifier for direct sign-in.
182+
/// </summary>
183+
public string Target { get; set; } = string.Empty;
184+
185+
/// <summary>
186+
/// The sign-in method.
187+
/// </summary>
188+
public string Method { get; set; } = string.Empty;
189+
190+
public static class Methods
191+
{
192+
/// <summary>
193+
/// Single sign-on method.
194+
/// </summary>
195+
public const string Sso = "sso";
196+
197+
/// <summary>
198+
/// Social sign-in method.
199+
/// </summary>
200+
public const string Social = "social";
201+
}
202+
}
203+
204+
/// <summary>
205+
/// Extra parameters to be passed to the authorization endpoint.
206+
/// </summary>
207+
public class ExtraParams : Dictionary<string, string>
208+
{
209+
}
210+
}
118211
}

src/Logto.AspNetCore.Authentication/extensions/AuthenticationBuilderExtensions.cs

+40-1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ namespace Logto.AspNetCore.Authentication;
99
using Microsoft.IdentityModel.Tokens;
1010
using System;
1111
using System.Collections.Generic;
12+
using System.Threading.Tasks;
1213

1314
/// <summary>
1415
/// Extension methods to configure Logto authentication.
@@ -101,11 +102,49 @@ private static void ConfigureOpenIdConnectOptions(OpenIdConnectOptions options,
101102
options.ClaimActions.MapAllExcept("nbf", "nonce", "c_hash", "at_hash");
102103
options.Events = new OpenIdConnectEvents
103104
{
105+
OnRedirectToIdentityProvider = context =>
106+
{
107+
if (context.Properties.Parameters.TryGetValue("first_screen", out var firstScreen))
108+
{
109+
context.ProtocolMessage.Parameters.Add("first_screen", firstScreen?.ToString());
110+
}
111+
112+
if (context.Properties.Parameters.TryGetValue("identifiers", out var identifiers))
113+
{
114+
context.ProtocolMessage.Parameters.Add("identifiers", identifiers?.ToString());
115+
}
116+
117+
if (context.Properties.Parameters.TryGetValue("direct_sign_in", out var directSignIn))
118+
{
119+
var directSignInOption = System.Text.Json.JsonSerializer.Deserialize<LogtoParameters.Authentication.DirectSignIn>(
120+
directSignIn?.ToString() ?? "{}"
121+
);
122+
if (directSignInOption != null && !string.IsNullOrEmpty(directSignInOption.Method) && !string.IsNullOrEmpty(directSignInOption.Target))
123+
{
124+
context.ProtocolMessage.Parameters.Add("direct_sign_in", $"{directSignInOption.Method}:{directSignInOption.Target}");
125+
}
126+
}
127+
128+
if (context.Properties.Parameters.TryGetValue("extra_params", out var extraParams))
129+
{
130+
var parameters = System.Text.Json.JsonSerializer.Deserialize<LogtoParameters.Authentication.ExtraParams>(
131+
extraParams?.ToString() ?? "{}"
132+
);
133+
if (parameters != null)
134+
{
135+
foreach (var param in parameters)
136+
{
137+
context.ProtocolMessage.Parameters.Add(param.Key, param.Value);
138+
}
139+
}
140+
}
141+
142+
return Task.CompletedTask;
143+
},
104144
OnRedirectToIdentityProviderForSignOut = async context =>
105145
{
106146
// Clean up the cookie when signing out.
107147
await context.HttpContext.SignOutAsync(cookieScheme);
108-
109148
// Rebuild parameters since we use <c>client_id</c> for sign-out, no need to use <c>id_token_hint</c>.
110149
context.ProtocolMessage.Parameters.Remove(OpenIdConnectParameterNames.IdTokenHint);
111150
context.ProtocolMessage.Parameters.Add(OpenIdConnectParameterNames.ClientId, logtoOptions.AppId);

0 commit comments

Comments
 (0)