diff --git a/TodoApi/Users/AccessTokenResponse.cs b/TodoApi/Users/AccessTokenResponse.cs
new file mode 100644
index 00000000..7c7f617f
--- /dev/null
+++ b/TodoApi/Users/AccessTokenResponse.cs
@@ -0,0 +1,45 @@
+using System.Text.Json.Serialization;
+
+// Copied from https://github.com/dotnet/aspnetcore/blob/bad855959a99257bc6f194dd19ecd6c9aeb03acb/src/Shared/BearerToken/DTO/AccessTokenResponse.cs
+
+namespace TodoApi;
+
+internal sealed class AccessTokenResponse
+{
+ ///
+ /// The value is always "Bearer" which indicates this response provides a "Bearer" token
+ /// in the form of an opaque .
+ ///
+ ///
+ /// This is serialized as "token_type": "Bearer" using System.Text.Json.
+ ///
+ [JsonPropertyName("token_type")]
+ public string TokenType { get; } = "Bearer";
+
+ ///
+ /// The opaque bearer token to send as part of the Authorization request header.
+ ///
+ ///
+ /// This is serialized as "access_token": "{AccessToken}" using System.Text.Json.
+ ///
+ [JsonPropertyName("access_token")]
+ public required string AccessToken { get; init; }
+
+ ///
+ /// The number of seconds before the expires.
+ ///
+ ///
+ /// This is serialized as "expires_in": "{ExpiresInSeconds}" using System.Text.Json.
+ ///
+ [JsonPropertyName("expires_in")]
+ public required long ExpiresInSeconds { get; init; }
+
+ ///
+ /// If set, this provides the ability to get a new access_token after it expires using a refresh endpoint.
+ ///
+ ///
+ /// This is serialized as "refresh_token": "{RefreshToken}" using System.Text.Json.
+ ///
+ [JsonPropertyName("refresh_token")]
+ public required string RefreshToken { get; init; }
+}
diff --git a/TodoApi/Users/UsersApi.cs b/TodoApi/Users/UsersApi.cs
index e02f5895..75da7d07 100644
--- a/TodoApi/Users/UsersApi.cs
+++ b/TodoApi/Users/UsersApi.cs
@@ -27,7 +27,7 @@ public static RouteGroupBuilder MapUsers(this IEndpointRouteBuilder routes)
return TypedResults.ValidationProblem(result.Errors.ToDictionary(e => e.Code, e => new[] { e.Description }));
});
- group.MapPost("/token", async Task> (UserInfo userInfo, UserManager userManager) =>
+ group.MapPost("/token", async Task>> (UserInfo userInfo, UserManager userManager) =>
{
var user = await userManager.FindByNameAsync(userInfo.Username);
@@ -41,7 +41,7 @@ public static RouteGroupBuilder MapUsers(this IEndpointRouteBuilder routes)
return TypedResults.SignIn(principal, authenticationScheme: BearerTokenDefaults.AuthenticationScheme);
});
- group.MapPost("/token/{provider}", async Task> (string provider, ExternalUserInfo userInfo, UserManager userManager) =>
+ group.MapPost("/token/{provider}", async Task>> (string provider, ExternalUserInfo userInfo, UserManager userManager) =>
{
var user = await userManager.FindByLoginAsync(provider, userInfo.ProviderKey);