From 47ac905b6407df640e9ee87daf2fbea4f6f24655 Mon Sep 17 00:00:00 2001 From: Oleksii Holub <1935960+Tyrrrz@users.noreply.github.com> Date: Thu, 21 Dec 2023 17:15:19 +0200 Subject: [PATCH 1/2] Standardize on a common terminology --- README.md | 4 +- .../PasswordlessController.cs | 4 +- .../Implementations/PasswordlessService.cs | 2 +- .../Helpers/PasswordlessSerializerContext.cs | 4 +- src/Passwordless/IPasswordlessClient.cs | 76 +++++-------------- ...ninOptions.cs => AuthenticationOptions.cs} | 4 +- ...onse.cs => AuthenticationTokenResponse.cs} | 4 +- src/Passwordless/PasswordlessClient.cs | 14 ++-- .../OldTests/PasswordlessServiceTests.cs | 9 ++- tests/Passwordless.Tests/TokenTests.cs | 26 +++---- 10 files changed, 57 insertions(+), 90 deletions(-) rename src/Passwordless/Models/{SigninOptions.cs => AuthenticationOptions.cs} (56%) rename src/Passwordless/Models/{SigninTokenResponse.cs => AuthenticationTokenResponse.cs} (52%) diff --git a/README.md b/README.md index f13fa97..4adb95a 100644 --- a/README.md +++ b/README.md @@ -92,11 +92,11 @@ public async Task GetRegisterToken(string alias) ### Verify user -Define an action or an endpoint to verify a signin token: +Define an action or an endpoint to verify an authentication token: ```csharp [HttpGet("/verify-signin")] -public async Task VerifySignInToken(string token) +public async Task VerifyAuthenticationToken(string token) { try { diff --git a/examples/Passwordless.Example/PasswordlessController.cs b/examples/Passwordless.Example/PasswordlessController.cs index a7ec552..e830b0c 100644 --- a/examples/Passwordless.Example/PasswordlessController.cs +++ b/examples/Passwordless.Example/PasswordlessController.cs @@ -61,11 +61,11 @@ public async Task GetRegisterToken(string alias) /// /// [HttpGet("/verify-signin")] - public async Task VerifySignInToken(string token) + public async Task VerifyAuthenticationToken(string token) { try { - var verifiedUser = await _passwordlessClient.VerifyTokenAsync(token); + var verifiedUser = await _passwordlessClient.VerifyAuthenticationTokenAsync(token); return Ok(verifiedUser); } catch (PasswordlessApiException e) diff --git a/src/Passwordless.AspNetCore/Services/Implementations/PasswordlessService.cs b/src/Passwordless.AspNetCore/Services/Implementations/PasswordlessService.cs index 674b225..a731cf4 100644 --- a/src/Passwordless.AspNetCore/Services/Implementations/PasswordlessService.cs +++ b/src/Passwordless.AspNetCore/Services/Implementations/PasswordlessService.cs @@ -261,7 +261,7 @@ public virtual async Task LoginUserAsync( { try { - var verifiedUser = await PasswordlessClient.VerifyTokenAsync(loginRequest.Token, cancellationToken); + var verifiedUser = await PasswordlessClient.VerifyAuthenticationTokenAsync(loginRequest.Token, cancellationToken); _logger.LogDebug("Attempting to find user in store by id {UserId}.", verifiedUser.UserId); var user = await UserStore.FindByIdAsync(verifiedUser.UserId, cancellationToken); diff --git a/src/Passwordless/Helpers/PasswordlessSerializerContext.cs b/src/Passwordless/Helpers/PasswordlessSerializerContext.cs index 774ff7a..123cadb 100644 --- a/src/Passwordless/Helpers/PasswordlessSerializerContext.cs +++ b/src/Passwordless/Helpers/PasswordlessSerializerContext.cs @@ -10,8 +10,8 @@ namespace Passwordless.Helpers; DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull)] [JsonSerializable(typeof(RegisterTokenResponse))] [JsonSerializable(typeof(RegisterOptions))] -[JsonSerializable(typeof(SigninTokenResponse))] -[JsonSerializable(typeof(SigninOptions))] +[JsonSerializable(typeof(AuthenticationTokenResponse))] +[JsonSerializable(typeof(AuthenticationOptions))] [JsonSerializable(typeof(VerifyTokenRequest))] [JsonSerializable(typeof(VerifiedUser))] [JsonSerializable(typeof(DeleteUserRequest))] diff --git a/src/Passwordless/IPasswordlessClient.cs b/src/Passwordless/IPasswordlessClient.cs index 9173e92..a3c1e30 100644 --- a/src/Passwordless/IPasswordlessClient.cs +++ b/src/Passwordless/IPasswordlessClient.cs @@ -11,41 +11,32 @@ namespace Passwordless; public interface IPasswordlessClient { /// - /// Creates a which will be used by your frontend to negotiate - /// the creation of a WebAuth credential. + /// Creates a register token which will be used by your frontend to negotiate the creation of a WebAuth credential. /// - /// The that will be used to configure your token. - /// - /// A task object representing the asynchronous operation containing the . - /// An exception containing details about the reason for failure. Task CreateRegisterTokenAsync( RegisterOptions options, CancellationToken cancellationToken = default ); /// - /// Creates a which can be used to authenticate on behalf of a user. + /// Manually generates an authentication token for the specified user, side-stepping the usual authentication flow. + /// This approach can be used to implement a "magic link"-style login and other similar scenarios. /// - /// The that will be used to configure your token. - /// - /// A task object representing the asynchronous operation containing the . - /// An exception containing details about the reason for failure. - Task GenerateSigninTokenAsync( - SigninOptions options, + Task GenerateAuthenticationTokenAsync( + AuthenticationOptions options, CancellationToken cancellationToken = default ); /// - /// Verifies that the given token is valid and returns information packed into it. - /// The token should have been generated via calling a signInWith* method from your frontend code. - /// If the token is not valid, an exception of type will be thrown. + /// Verifies that the specified authentication token is valid and returns the information packed into it. + /// The token should have been generated by calling one of the signInWith* methods from your frontend, + /// or, in specific scenarios, by calling from the backend. /// - /// The token to verify. - /// - /// A task object representing the asynchronous operation containing the . - /// An exception containing details about the reason for failure. - Task VerifyTokenAsync( - string verifyToken, + /// + /// If the token is not valid, an exception of type will be thrown. + /// + Task VerifyAuthenticationTokenAsync( + string authenticationToken, CancellationToken cancellationToken = default ); @@ -57,81 +48,56 @@ Task GetUsersCountAsync( ); /// - /// List all the for the account associated with your ApiSecret. + /// Lists all users in the app. /// - /// - /// A task object representing the asynchronous operation containing the . - /// An exception containing details about the reason for failure. Task> ListUsersAsync( CancellationToken cancellationToken = default ); /// - /// Deletes a user. + /// Deletes the user with the specified ID. /// - /// The id of the user that should be deleted. - /// - /// A task object representing the asynchronous operation. - /// An exception containing details about the reason for failure. Task DeleteUserAsync( string userId, CancellationToken cancellationToken = default ); /// - /// List all the for a given user. + /// Lists all aliases for the user with the specified ID. /// - /// The userId of the user for which the aliases will be returned. - /// - /// A task object representing the asynchronous operation containing the . - /// An exception containing details about the reason for failure. Task> ListAliasesAsync( string userId, CancellationToken cancellationToken = default ); /// - /// Sets one or more aliases to an existing user and removes existing aliases that are not included in the request. + /// Sets one or more aliases for an existing user and removes existing aliases + /// that are not included in the request. /// - /// - /// - /// Task SetAliasAsync( SetAliasRequest request, CancellationToken cancellationToken = default ); /// - /// List all the for a given user. + /// Lists all credentials for the user with the specified ID. /// - /// The userId of the user for which the credentials will be returned. - /// - /// A task object representing the asynchronous operation containing the . - /// An exception containing details about the reason for failure. Task> ListCredentialsAsync( string userId, CancellationToken cancellationToken = default ); /// - /// Attempts to delete a credential via the supplied id. + /// Attempts to delete a credential with the specified ID. /// - /// The id of a credential representing as a Base64 URL encoded . - /// - /// A task object representing the asynchronous operation. - /// An exception containing details about the reason for failure. Task DeleteCredentialAsync( string id, CancellationToken cancellationToken = default ); /// - /// Attempts to delete a credential via the supplied id. + /// Attempts to delete a credential with the specified ID. /// - /// The id of a credential representing as a Base64 URL encoded . - /// - /// A task object representing the asynchronous operation. - /// An exception containing details about the reason for failure. Task DeleteCredentialAsync( byte[] id, CancellationToken cancellationToken = default diff --git a/src/Passwordless/Models/SigninOptions.cs b/src/Passwordless/Models/AuthenticationOptions.cs similarity index 56% rename from src/Passwordless/Models/SigninOptions.cs rename to src/Passwordless/Models/AuthenticationOptions.cs index 09950c3..5e2cf8d 100644 --- a/src/Passwordless/Models/SigninOptions.cs +++ b/src/Passwordless/Models/AuthenticationOptions.cs @@ -1,10 +1,10 @@ namespace Passwordless.Models; -public class SigninOptions +public class AuthenticationOptions { public string UserId { get; } - public SigninOptions(string userId) + public AuthenticationOptions(string userId) { UserId = userId; } diff --git a/src/Passwordless/Models/SigninTokenResponse.cs b/src/Passwordless/Models/AuthenticationTokenResponse.cs similarity index 52% rename from src/Passwordless/Models/SigninTokenResponse.cs rename to src/Passwordless/Models/AuthenticationTokenResponse.cs index 74385d5..e2e4b21 100644 --- a/src/Passwordless/Models/SigninTokenResponse.cs +++ b/src/Passwordless/Models/AuthenticationTokenResponse.cs @@ -1,8 +1,8 @@ namespace Passwordless.Models; -public class SigninTokenResponse +public class AuthenticationTokenResponse { - public SigninTokenResponse(string token) + public AuthenticationTokenResponse(string token) { Token = token; } diff --git a/src/Passwordless/PasswordlessClient.cs b/src/Passwordless/PasswordlessClient.cs index f89bb34..da957e3 100644 --- a/src/Passwordless/PasswordlessClient.cs +++ b/src/Passwordless/PasswordlessClient.cs @@ -80,30 +80,30 @@ public async Task CreateRegisterTokenAsync( } /// - public async Task GenerateSigninTokenAsync( - SigninOptions options, + public async Task GenerateAuthenticationTokenAsync( + AuthenticationOptions options, CancellationToken cancellationToken = default) { using var response = await _http.PostAsJsonAsync("signin/generate-token", options, - PasswordlessSerializerContext.Default.SigninOptions, + PasswordlessSerializerContext.Default.AuthenticationOptions, cancellationToken ); response.EnsureSuccessStatusCode(); return (await response.Content.ReadFromJsonAsync( - PasswordlessSerializerContext.Default.SigninTokenResponse, + PasswordlessSerializerContext.Default.AuthenticationTokenResponse, cancellationToken))!; } /// - public async Task VerifyTokenAsync( - string verifyToken, + public async Task VerifyAuthenticationTokenAsync( + string authenticationToken, CancellationToken cancellationToken = default) { using var response = await _http.PostAsJsonAsync("signin/verify", - new VerifyTokenRequest(verifyToken), + new VerifyTokenRequest(authenticationToken), PasswordlessSerializerContext.Default.VerifyTokenRequest, cancellationToken ); diff --git a/tests/Passwordless.AspNetCore.Tests/OldTests/PasswordlessServiceTests.cs b/tests/Passwordless.AspNetCore.Tests/OldTests/PasswordlessServiceTests.cs index 3428581..098699b 100644 --- a/tests/Passwordless.AspNetCore.Tests/OldTests/PasswordlessServiceTests.cs +++ b/tests/Passwordless.AspNetCore.Tests/OldTests/PasswordlessServiceTests.cs @@ -16,6 +16,7 @@ using Passwordless.AspNetCore.Services.Implementations; using Passwordless.Models; using Xunit; +using AuthenticationOptions = Microsoft.AspNetCore.Authentication.AuthenticationOptions; namespace Passwordless.AspNetCore.Tests.OldTests; @@ -206,7 +207,7 @@ public async Task LoginUserAsync_UsesDefaultSchemeIfNoneSpecified() await _testUserStore.CreateAsync(user); _mockPasswordlessClient - .Setup(s => s.VerifyTokenAsync("test_token", default)) + .Setup(s => s.VerifyAuthenticationTokenAsync("test_token", default)) .ReturnsAsync(verifiedUser); _mockUserClaimsPrincipalFactory @@ -248,7 +249,7 @@ public async Task LoginUserAsync_UsesOurOptionIfSpecified() await _testUserStore.CreateAsync(user); _mockPasswordlessClient - .Setup(s => s.VerifyTokenAsync("test_token", default)) + .Setup(s => s.VerifyAuthenticationTokenAsync("test_token", default)) .ReturnsAsync(verifiedUser); _mockUserClaimsPrincipalFactory @@ -297,7 +298,7 @@ public async Task LoginUserAsync_TriesAuthenticationOptionsIfOursIsNull() await _testUserStore.CreateAsync(user); _mockPasswordlessClient - .Setup(s => s.VerifyTokenAsync("test_token", default)) + .Setup(s => s.VerifyAuthenticationTokenAsync("test_token", default)) .ReturnsAsync(verifiedUser); _mockUserClaimsPrincipalFactory @@ -329,7 +330,7 @@ public async Task LoginUserAsync_UserDoesNotExist_ReturnsUnauthorized() _fixture.Create(), _fixture.Create()); _mockPasswordlessClient - .Setup(s => s.VerifyTokenAsync("test_token", default)) + .Setup(s => s.VerifyAuthenticationTokenAsync("test_token", default)) .ReturnsAsync(verifiedUser); var sut = CreateSut(); diff --git a/tests/Passwordless.Tests/TokenTests.cs b/tests/Passwordless.Tests/TokenTests.cs index 94970cd..92c662f 100644 --- a/tests/Passwordless.Tests/TokenTests.cs +++ b/tests/Passwordless.Tests/TokenTests.cs @@ -31,14 +31,14 @@ public async Task I_can_create_a_register_token() } [Fact] - public async Task I_can_generate_a_signin_token() + public async Task I_can_generate_an_authentication_token() { // Arrange var passwordless = await Api.CreateClientAsync(); // Act - var response = await passwordless.GenerateSigninTokenAsync( - new SigninOptions("user123") + var response = await passwordless.GenerateAuthenticationTokenAsync( + new AuthenticationOptions("user123") ); // Assert @@ -47,17 +47,17 @@ public async Task I_can_generate_a_signin_token() } [Fact] - public async Task I_can_verify_a_valid_signin_token() + public async Task I_can_verify_a_valid_authentication_token() { // Arrange var passwordless = await Api.CreateClientAsync(); - var token = (await passwordless.GenerateSigninTokenAsync( - new SigninOptions("user123") + var token = (await passwordless.GenerateAuthenticationTokenAsync( + new AuthenticationOptions("user123") )).Token; // Act - var response = await passwordless.VerifyTokenAsync(token); + var response = await passwordless.VerifyAuthenticationTokenAsync(token); // Assert response.Success.Should().BeTrue(); @@ -65,14 +65,14 @@ public async Task I_can_verify_a_valid_signin_token() } [Fact] - public async Task I_can_try_to_verify_a_poorly_formatted_signin_token_and_get_an_error() + public async Task I_can_try_to_verify_a_poorly_formatted_authentication_token_and_get_an_error() { // Arrange var passwordless = await Api.CreateClientAsync(); // Act & assert var ex = await Assert.ThrowsAnyAsync(async () => - await passwordless.VerifyTokenAsync("invalid") + await passwordless.VerifyAuthenticationTokenAsync("invalid") ); ex.Details.Status.Should().Be(400); @@ -80,14 +80,14 @@ await passwordless.VerifyTokenAsync("invalid") } [Fact] - public async Task I_can_try_to_verify_a_tampered_signin_token_and_get_an_error() + public async Task I_can_try_to_verify_a_tampered_authentication_token_and_get_an_error() { // Arrange var passwordless = await Api.CreateClientAsync(); // Act & assert var ex = await Assert.ThrowsAnyAsync(async () => - await passwordless.VerifyTokenAsync("verify_something_that_looks_like_a_token_but_is_not") + await passwordless.VerifyAuthenticationTokenAsync("verify_something_that_looks_like_a_token_but_is_not") ); ex.Details.Status.Should().Be(400); @@ -95,14 +95,14 @@ await passwordless.VerifyTokenAsync("verify_something_that_looks_like_a_token_bu } [Fact] - public async Task I_can_try_to_verify_an_invalid_signin_token_and_get_an_error() + public async Task I_can_try_to_verify_an_invalid_authentication_token_and_get_an_error() { // Arrange var passwordless = await Api.CreateClientAsync(); // Act & assert var ex = await Assert.ThrowsAnyAsync(async () => - await passwordless.VerifyTokenAsync( + await passwordless.VerifyAuthenticationTokenAsync( "verify_" + "k8Qg4kXVl8D2aunn__jMT7td5endUueS9zEG8zIsu0lqQjfFAQXcABPX_wlDNbBlTNiB2SQ5MjQ0ZmUzYS0wOGExLTRlMTctOTMwZS1i" + "YWZhNmM0OWJiOGWucGFzc2tleV9zaWduaW7AwMDAwMDA2SQ3NGUxMzFjOS0yNDZhLTRmNzYtYjIxMS1jNzBkZWQ1Mjg2YzLX_wlDJIBl" + From 78501415667ef60a6579feea742eac959c752486 Mon Sep 17 00:00:00 2001 From: Oleksii Holub <1935960+Tyrrrz@users.noreply.github.com> Date: Thu, 21 Dec 2023 17:17:01 +0200 Subject: [PATCH 2/2] asd --- examples/Passwordless.Example/PasswordlessController.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/examples/Passwordless.Example/PasswordlessController.cs b/examples/Passwordless.Example/PasswordlessController.cs index e830b0c..28d9050 100644 --- a/examples/Passwordless.Example/PasswordlessController.cs +++ b/examples/Passwordless.Example/PasswordlessController.cs @@ -25,8 +25,6 @@ public PasswordlessController(IPasswordlessClient passwordlessClient) /// signed in users to add a Key to their own account. /// Please see: https://docs.passwordless.dev/guide/api.html#register-token /// - /// - /// [HttpGet("/create-token")] public async Task GetRegisterToken(string alias) { @@ -59,7 +57,6 @@ public async Task GetRegisterToken(string alias) /// This is as easy as POST'ing it to together with your ApiSecret. /// Please see: https://docs.passwordless.dev/guide/api.html#signin-verify /// - /// [HttpGet("/verify-signin")] public async Task VerifyAuthenticationToken(string token) {