From ec5cef7d361b4f540331098395af4f4466fb1b5d Mon Sep 17 00:00:00 2001 From: Nishchal Date: Sun, 4 Jul 2021 19:32:18 +0700 Subject: [PATCH] feat(auth): add login and refresh mutation BREAKING CHANGE: Older rest endpoint to login and refresh removed --- .../BadBasicAuthorizationDataException.cs | 11 -- .../Authentication/SessionController.cs | 150 ------------------ .../ViewModels/JwtRefreshViewModels.cs | 7 - .../Exceptions/InvalidTokenTypeException.cs | 11 ++ .../Exceptions/MissingHeaderException.cs | 11 ++ .../Extensions/LoginRequestExtension.cs | 22 +++ Micro.Auth.Api/GraphQL/Extensions/Tokens.cs | 53 +++++++ Micro.Auth.Api/GraphQL/Mutation.cs | 10 +- Micro.Auth.Api/GraphQL/Types/TokensType.cs | 15 ++ .../Internal/StartupExtensions/GraphQl.cs | 1 + .../UserData/Extensions/IpAddressExtension.cs | 6 + .../UserData/Extensions/LocationExtension.cs | 5 + .../UserData/Extensions/UserAgentExtension.cs | 7 + .../Exceptions/InvalidCredentialsException.cs | 11 ++ .../Sessions/LoginSuccessResponse.cs | 9 +- .../Sessions/LoginViewModel.cs | 21 +-- .../Sessions/SessionService.cs | 60 ++++--- Micro.Auth.Storage/RefreshTokenRepository.cs | 6 +- 18 files changed, 197 insertions(+), 219 deletions(-) delete mode 100644 Micro.Auth.Api/Authentication/Exceptions/BadBasicAuthorizationDataException.cs delete mode 100644 Micro.Auth.Api/Authentication/SessionController.cs delete mode 100644 Micro.Auth.Api/Authentication/ViewModels/JwtRefreshViewModels.cs create mode 100644 Micro.Auth.Api/GraphQL/Extensions/Exceptions/InvalidTokenTypeException.cs create mode 100644 Micro.Auth.Api/GraphQL/Extensions/Exceptions/MissingHeaderException.cs create mode 100644 Micro.Auth.Api/GraphQL/Extensions/LoginRequestExtension.cs create mode 100644 Micro.Auth.Api/GraphQL/Extensions/Tokens.cs create mode 100644 Micro.Auth.Api/GraphQL/Types/TokensType.cs create mode 100644 Micro.Auth.Business/Sessions/Exceptions/InvalidCredentialsException.cs diff --git a/Micro.Auth.Api/Authentication/Exceptions/BadBasicAuthorizationDataException.cs b/Micro.Auth.Api/Authentication/Exceptions/BadBasicAuthorizationDataException.cs deleted file mode 100644 index 870c4de..0000000 --- a/Micro.Auth.Api/Authentication/Exceptions/BadBasicAuthorizationDataException.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System; - -namespace Micro.Auth.Api.Authentication.Exceptions -{ - public class BadBasicAuthorizationDataException : Exception - { - public BadBasicAuthorizationDataException(string? message, Exception? innerException) : base(message, innerException) - { - } - } -} diff --git a/Micro.Auth.Api/Authentication/SessionController.cs b/Micro.Auth.Api/Authentication/SessionController.cs deleted file mode 100644 index f144c5e..0000000 --- a/Micro.Auth.Api/Authentication/SessionController.cs +++ /dev/null @@ -1,150 +0,0 @@ -using System; -using System.ComponentModel.DataAnnotations; -using System.Text; -using System.Threading.Tasks; -using App.Metrics; -using Micro.Auth.Api.Authentication.Exceptions; -using Micro.Auth.Api.Authentication.ViewModels; -using Micro.Auth.Api.Internal.UserData.Extensions; -using Micro.Auth.Api.Internal.ValidationAttributes; -using Micro.Auth.Business.Internal.Measurements; -using Micro.Auth.Business.Sessions; -using Micro.Auth.Storage.Exceptions; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Mvc; -using Microsoft.Extensions.Logging; - -namespace Micro.Auth.Api.Authentication -{ - [Route("api/[controller]")] - [ApiController] - public class SessionController : ControllerBase - { - private readonly ILogger _logger; - private readonly IMetrics _metrics; - private readonly ISessionService _sessionService; - - public SessionController(ILogger logger, IMetrics metrics, ISessionService sessionService) - { - _logger = logger; - _metrics = metrics; - _sessionService = sessionService; - } - - [HttpPost("new")] - public async Task New([FromHeader(Name = "Authorization")][Required][StartsWith("Basic ")] string authorization) - { - try - { - var (login, password) = GetBasicAuthData(authorization); - var (result, response) = await _sessionService.Login(new LoginRequest - { - Login = login, - Password = password, - Location = this.GetRoughLocation(), - IpAddress = this.GetIpAddress(), - UserAgent = this.GetUserAgent(), - }); - if (!result.Succeeded) - { - var problem = ProcessErrorResult(result); - _metrics.SessionController().MarkBadLoginAttempt(problem); - return Unauthorized(new ProblemDetails - { - Title = problem - }); - } - - _metrics.SessionController().MarkSuccessfulLoginAttempt(); - return Ok(response); - } - catch (BadBasicAuthorizationDataException e) - { - _metrics.SessionController().MarkBadAuthData(); - _logger.LogInformation(e.Message, e); - return BadRequest(new ProblemDetails - { - Title = "authorization data is invalid" - }); - } - catch (Exception e) - { - _metrics.SessionController().MarkLoginException(e.GetType().FullName); - _logger.LogError(e.Message, e); - return StatusCode(StatusCodes.Status500InternalServerError, new ProblemDetails - { - Title = "error handling request" - }); - } - } - - [HttpPost("refresh")] - [ProducesResponseType(typeof(RefreshTokenSuccessResponse), StatusCodes.Status200OK)] - [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status400BadRequest)] - [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status404NotFound)] - [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status500InternalServerError)] - public async Task Refresh( - [FromHeader(Name = "Authorization")] - [Required] - [StartsWith("Bearer")] - string authorization - ) - { - var token = GetBearerToken(authorization); - try - { - var jwt = await _sessionService.Refresh(token); - return Ok(new RefreshTokenSuccessResponse - { - Jwt = jwt - }); - } - catch (RefreshTokenNotFoundException) - { - _metrics.SessionController().MarkTokenNotFoundInDb(); - return NotFound(new ProblemDetails - { - Title = "token is invalid" - }); - } - catch (Exception e) - { - _logger.LogCritical(e, "error processing request"); - _metrics.SessionController().MarkException(e.GetType().FullName); - return StatusCode(StatusCodes.Status500InternalServerError, new ProblemDetails - { - Detail = "error processing request" - }); - } - } - - private static string ProcessErrorResult(Microsoft.AspNetCore.Identity.SignInResult result) - { - if (result.IsLockedOut) - { - return "Account Locked Out"; - } - - return result.IsNotAllowed ? "Login not allowed" : "Wrong Credentials"; - } - - private static string GetBearerToken(string authorizationHeader) - { - return authorizationHeader.Substring("Bearer ".Length).Trim(); - } - - private static (string, string) GetBasicAuthData(string authorizationHeader) - { - try - { - var token = authorizationHeader.Substring("Basic ".Length).Trim(); - var parts = Encoding.UTF8.GetString(Convert.FromBase64String(token)).Split(":"); - return (parts[0], parts[1]); - } - catch (Exception e) - { - throw new BadBasicAuthorizationDataException("bad data", e); - } - } - } -} diff --git a/Micro.Auth.Api/Authentication/ViewModels/JwtRefreshViewModels.cs b/Micro.Auth.Api/Authentication/ViewModels/JwtRefreshViewModels.cs deleted file mode 100644 index a313804..0000000 --- a/Micro.Auth.Api/Authentication/ViewModels/JwtRefreshViewModels.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Micro.Auth.Api.Authentication.ViewModels -{ - public class RefreshTokenSuccessResponse - { - public string Jwt { set; get; } - } -} diff --git a/Micro.Auth.Api/GraphQL/Extensions/Exceptions/InvalidTokenTypeException.cs b/Micro.Auth.Api/GraphQL/Extensions/Exceptions/InvalidTokenTypeException.cs new file mode 100644 index 0000000..53e266e --- /dev/null +++ b/Micro.Auth.Api/GraphQL/Extensions/Exceptions/InvalidTokenTypeException.cs @@ -0,0 +1,11 @@ +using System; + +namespace Micro.Auth.Api.GraphQL.Extensions.Exceptions +{ + public class InvalidTokenTypeException : Exception + { + public InvalidTokenTypeException(string expectedType) : base($"{expectedType} token not found") + { + } + } +} diff --git a/Micro.Auth.Api/GraphQL/Extensions/Exceptions/MissingHeaderException.cs b/Micro.Auth.Api/GraphQL/Extensions/Exceptions/MissingHeaderException.cs new file mode 100644 index 0000000..0e776e4 --- /dev/null +++ b/Micro.Auth.Api/GraphQL/Extensions/Exceptions/MissingHeaderException.cs @@ -0,0 +1,11 @@ +using System; + +namespace Micro.Auth.Api.GraphQL.Extensions.Exceptions +{ + public class MissingHeaderException : Exception + { + public MissingHeaderException(string headerName) : base($"Missing {headerName} header") + { + } + } +} diff --git a/Micro.Auth.Api/GraphQL/Extensions/LoginRequestExtension.cs b/Micro.Auth.Api/GraphQL/Extensions/LoginRequestExtension.cs new file mode 100644 index 0000000..e865f3f --- /dev/null +++ b/Micro.Auth.Api/GraphQL/Extensions/LoginRequestExtension.cs @@ -0,0 +1,22 @@ +using Micro.Auth.Api.Internal.UserData.Extensions; +using Micro.Auth.Business.Sessions; +using Microsoft.AspNetCore.Http; + +namespace Micro.Auth.Api.GraphQL.Extensions +{ + public static class LoginRequestExtension + { + public static LoginRequest GetLoginRequest(this IHttpContextAccessor httpContextAccessor) + { + var (login, password) = httpContextAccessor.MustGetBasicToken(); + return new LoginRequest + { + Login = login, + Password = password, + IpAddress = httpContextAccessor.GetIpAddress(), + UserAgent = httpContextAccessor.GetUserAgent(), + Location = httpContextAccessor.GetRoughLocation() + }; + } + } +} diff --git a/Micro.Auth.Api/GraphQL/Extensions/Tokens.cs b/Micro.Auth.Api/GraphQL/Extensions/Tokens.cs new file mode 100644 index 0000000..ba75faa --- /dev/null +++ b/Micro.Auth.Api/GraphQL/Extensions/Tokens.cs @@ -0,0 +1,53 @@ +using System; +using System.Text; +using Micro.Auth.Api.GraphQL.Extensions.Exceptions; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Primitives; + +namespace Micro.Auth.Api.GraphQL.Extensions +{ + public static class Tokens + { + public static string MustGetBearerToken(this IHttpContextAccessor httpContextAccessor) + { + var headerValue = httpContextAccessor.MustGetAuthHeader(); + if (!headerValue.StartsWith("Bearer ")) + { + throw new InvalidTokenTypeException("Bearer"); + } + return headerValue.Substring("Bearer ".Length).Trim(); + } + + private static string MustGetAuthHeader(this IHttpContextAccessor httpContextAccessor) + { + var header = StringValues.Empty; + var exists = httpContextAccessor.HttpContext?.Request.Headers.TryGetValue("Authorization", out header); + if (exists == false || header.ToString() == "") + { + throw new MissingHeaderException("Authorization"); + } + + return header.ToString(); + } + + public static (string, string) MustGetBasicToken(this IHttpContextAccessor httpContextAccessor) + { + try + { + var headerValue = httpContextAccessor.MustGetAuthHeader(); + if (!headerValue.StartsWith("Basic ")) + { + throw new InvalidTokenTypeException("Basic"); + } + + var token = headerValue.Substring("Basic ".Length).Trim(); + var parts = Encoding.UTF8.GetString(Convert.FromBase64String(token)).Split(":"); + return (parts[0], parts[1]); + } + catch (Exception e) + { + throw new InvalidTokenTypeException(e.Message); + } + } + } +} diff --git a/Micro.Auth.Api/GraphQL/Mutation.cs b/Micro.Auth.Api/GraphQL/Mutation.cs index 78ae90c..cec31c9 100644 --- a/Micro.Auth.Api/GraphQL/Mutation.cs +++ b/Micro.Auth.Api/GraphQL/Mutation.cs @@ -1,12 +1,14 @@ using GraphQL; using GraphQL.Types; using Micro.Auth.Api.GraphQL.Directives.Extensions; +using Micro.Auth.Api.GraphQL.Extensions; using Micro.Auth.Api.GraphQL.Inputs; using Micro.Auth.Api.GraphQL.Types; using Micro.Auth.Api.Internal.UserData.Extensions; using Micro.Auth.Business.Common; using Micro.Auth.Business.EmailVerification; using Micro.Auth.Business.PasswordManager; +using Micro.Auth.Business.Sessions; using Micro.Auth.Business.Users; using Microsoft.AspNetCore.Http; @@ -14,12 +16,18 @@ namespace Micro.Auth.Api.GraphQL { public class Mutation : ObjectGraphType { - public Mutation(IUserService userService, IPasswordManager passwordManager, IEmailVerificationService verification, IHttpContextAccessor contextAccessor) + public Mutation(IUserService userService, IPasswordManager passwordManager, IEmailVerificationService verification, ISessionService sessionService, IHttpContextAccessor contextAccessor) { FieldAsync, User>("register", arguments: new QueryArguments(RegisterInputType.BuildArgument()), resolve: x => userService.Create(x.GetArgument("input"))); + FieldAsync, string>("refreshToken", + resolve: x => sessionService.Refresh(contextAccessor.MustGetBearerToken())); + + FieldAsync, LoginSuccessResponse>("login", + resolve: x => sessionService.Login(contextAccessor.GetLoginRequest())); + FieldAsync, User>("verifyEmail", arguments: new QueryArguments(VerifyEmailInputType.BuildArgument()), resolve: x => verification.ConfirmEmail(x.GetArgument("input"))); diff --git a/Micro.Auth.Api/GraphQL/Types/TokensType.cs b/Micro.Auth.Api/GraphQL/Types/TokensType.cs new file mode 100644 index 0000000..4d610e4 --- /dev/null +++ b/Micro.Auth.Api/GraphQL/Types/TokensType.cs @@ -0,0 +1,15 @@ +using Micro.Auth.Business.Sessions; + +namespace Micro.Auth.Api.GraphQL.Types +{ + public sealed class TokensType : Micro.GraphQL.Federation.ObjectGraphType + { + public TokensType() + { + Name = "Token"; + Field("jwt", x => x.Jwt).Description("JWT"); + Field("refreshToken", x => x.RefreshToken, true) + .Description("Once JWT expires, use this token to create a new session"); + } + } +} diff --git a/Micro.Auth.Api/Internal/StartupExtensions/GraphQl.cs b/Micro.Auth.Api/Internal/StartupExtensions/GraphQl.cs index 04410e6..91cef56 100644 --- a/Micro.Auth.Api/Internal/StartupExtensions/GraphQl.cs +++ b/Micro.Auth.Api/Internal/StartupExtensions/GraphQl.cs @@ -27,6 +27,7 @@ public static void ConfigureGraphQl(this IServiceCollection services) services.AddTransient(); services.AddTransient(); services.AddTransient(); + services.AddTransient(); services.AddTransient(); services.AddTransient(); services.AddTransient(); diff --git a/Micro.Auth.Api/Internal/UserData/Extensions/IpAddressExtension.cs b/Micro.Auth.Api/Internal/UserData/Extensions/IpAddressExtension.cs index 4171808..53f8f86 100644 --- a/Micro.Auth.Api/Internal/UserData/Extensions/IpAddressExtension.cs +++ b/Micro.Auth.Api/Internal/UserData/Extensions/IpAddressExtension.cs @@ -1,4 +1,5 @@ using System.Net; +using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; namespace Micro.Auth.Api.Internal.UserData.Extensions @@ -10,5 +11,10 @@ public static IPAddress GetIpAddress(this ControllerBase controller) // todo: this might not be accurate behind a load balancer, so we might have to get X-Forwarded-For return controller?.HttpContext?.Connection?.RemoteIpAddress; } + public static IPAddress GetIpAddress(this IHttpContextAccessor ctx) + { + // todo: this might not be accurate behind a load balancer, so we might have to get X-Forwarded-For + return ctx.HttpContext?.Connection.RemoteIpAddress; + } } } diff --git a/Micro.Auth.Api/Internal/UserData/Extensions/LocationExtension.cs b/Micro.Auth.Api/Internal/UserData/Extensions/LocationExtension.cs index 29cf9e0..8b12d74 100644 --- a/Micro.Auth.Api/Internal/UserData/Extensions/LocationExtension.cs +++ b/Micro.Auth.Api/Internal/UserData/Extensions/LocationExtension.cs @@ -1,3 +1,4 @@ +using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; namespace Micro.Auth.Api.Internal.UserData.Extensions @@ -8,5 +9,9 @@ public static string GetRoughLocation(this ControllerBase controller) { return "Bangkok"; } + public static string GetRoughLocation(this IHttpContextAccessor ctx) + { + return "Bangkok"; + } } } diff --git a/Micro.Auth.Api/Internal/UserData/Extensions/UserAgentExtension.cs b/Micro.Auth.Api/Internal/UserData/Extensions/UserAgentExtension.cs index f3e9143..5fde79c 100644 --- a/Micro.Auth.Api/Internal/UserData/Extensions/UserAgentExtension.cs +++ b/Micro.Auth.Api/Internal/UserData/Extensions/UserAgentExtension.cs @@ -1,3 +1,4 @@ +using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Primitives; @@ -11,5 +12,11 @@ public static class UserAgentExtension var containsData = controller?.HttpContext?.Request?.Headers?.TryGetValue("User-Agent", out userAgent); return containsData.HasValue && containsData.Value ? userAgent.ToString() : null; } + public static string? GetUserAgent(this IHttpContextAccessor ctx) + { + var userAgent = StringValues.Empty; + var containsData = ctx?.HttpContext?.Request?.Headers?.TryGetValue("User-Agent", out userAgent); + return containsData.HasValue && containsData.Value ? userAgent.ToString() : null; + } } } diff --git a/Micro.Auth.Business/Sessions/Exceptions/InvalidCredentialsException.cs b/Micro.Auth.Business/Sessions/Exceptions/InvalidCredentialsException.cs new file mode 100644 index 0000000..6cf5b44 --- /dev/null +++ b/Micro.Auth.Business/Sessions/Exceptions/InvalidCredentialsException.cs @@ -0,0 +1,11 @@ +using System; + +namespace Micro.Auth.Business.Sessions.Exceptions +{ + public class InvalidCredentialsException : Exception + { + public InvalidCredentialsException(string message) : base(message) + { + } + } +} diff --git a/Micro.Auth.Business/Sessions/LoginSuccessResponse.cs b/Micro.Auth.Business/Sessions/LoginSuccessResponse.cs index 88e8696..5c1bc29 100644 --- a/Micro.Auth.Business/Sessions/LoginSuccessResponse.cs +++ b/Micro.Auth.Business/Sessions/LoginSuccessResponse.cs @@ -1,12 +1,9 @@ +#nullable enable namespace Micro.Auth.Business.Sessions { - public class LoginSuccessResponse : ServiceAccountLoginResponse + public class LoginSuccessResponse { public string RefreshToken { set; get; } - } - - public class ServiceAccountLoginResponse - { - public string Jwt { set; get; } + public string? Jwt { set; get; } } } diff --git a/Micro.Auth.Business/Sessions/LoginViewModel.cs b/Micro.Auth.Business/Sessions/LoginViewModel.cs index 88623ff..1ce6d6c 100644 --- a/Micro.Auth.Business/Sessions/LoginViewModel.cs +++ b/Micro.Auth.Business/Sessions/LoginViewModel.cs @@ -1,32 +1,13 @@ -using System; using System.Net; -using Micro.Auth.Storage; namespace Micro.Auth.Business.Sessions { - public class LoginRequest + public record LoginRequest { public string Login { set; get; } public string Password { set; get; } public string UserAgent { set; get; } public IPAddress IpAddress { set; get; } public string Location { set; get; } - public Micro.Auth.Storage.User User { set; get; } - } - - public static class LoginRequestExtensions - { - public static RefreshToken ToRefreshToken(this LoginRequest request, string tokenValue) - { - return new RefreshToken - { - Location = request.Location, - Useragent = request.UserAgent, - User = request.User.Id, - IpAddress = request.IpAddress, - LastUsed = DateTime.Now, - Value = tokenValue - }; - } } } diff --git a/Micro.Auth.Business/Sessions/SessionService.cs b/Micro.Auth.Business/Sessions/SessionService.cs index 6b14b39..9ba8ddb 100644 --- a/Micro.Auth.Business/Sessions/SessionService.cs +++ b/Micro.Auth.Business/Sessions/SessionService.cs @@ -1,18 +1,20 @@ using System; -using System.Collections.Generic; using System.Threading.Tasks; using Micro.Auth.Business.Internal.Extensions; using Micro.Auth.Business.Internal.Tokens; +using Micro.Auth.Business.Sessions.Exceptions; +using Micro.Auth.Business.Users; using Micro.Auth.Common; using Micro.Auth.Storage; using Microsoft.AspNetCore.Identity; +using User = Micro.Auth.Storage.User; namespace Micro.Auth.Business.Sessions { public interface ISessionService { Task Refresh(string token); - Task<(SignInResult, ServiceAccountLoginResponse)> Login(LoginRequest loginRequest); + Task Login(LoginRequest request); } public class SessionService : ISessionService @@ -48,40 +50,52 @@ public async Task Refresh(string token) return _tokenFactory.GenerateJwtToken(principal); } - public async Task<(SignInResult, ServiceAccountLoginResponse)> Login(LoginRequest loginRequest) + public async Task Login(LoginRequest request) { - var user = await _userManager.GetUserByLogin(loginRequest.Login); - loginRequest.User = user; - return await AuthenticateUser(loginRequest); - } - - private async Task<(SignInResult signInResult, ServiceAccountLoginResponse login)> AuthenticateUser(LoginRequest login) - { - if (login.User == null) + var user = await _userManager.GetUserByLogin(request.Login); + if (user == null) { - throw new ArgumentNullException(nameof(login), "not null expected"); + throw new UserNotFoundException(); } - var signInResult = await _signInManager.PasswordSignInAsync(login.User, login.Password, false, true); + + var signInResult = await _signInManager.PasswordSignInAsync(user, request.Password, false, true); if (!signInResult.Succeeded) { - return (signInResult, null); + throw new InvalidCredentialsException(ProcessErrorResult(signInResult)); } - var principal = await _signInManager.CreateUserPrincipalAsync(login.User); + var principal = await _signInManager.CreateUserPrincipalAsync(user); var jwt = _tokenFactory.GenerateJwtToken(principal); - if (!principal.IsServiceAccount()) + if (principal.IsServiceAccount()) { - var refreshToken = await _refreshTokenRepository.Create(login.ToRefreshToken(_uuidService.GenerateUuId("session"))); - return (signInResult, new LoginSuccessResponse + return new LoginSuccessResponse { Jwt = jwt, - RefreshToken = refreshToken.Value - }); + }; } - var res = new ServiceAccountLoginResponse + var refreshToken = await _refreshTokenRepository.Create(new RefreshToken + { + Location = request.Location, + User = user.Id, + Useragent = request.UserAgent, + IpAddress = request.IpAddress, + LastUsed = DateTime.Now, + Value = _uuidService.GenerateUuId("session"), + }); + return new LoginSuccessResponse { - Jwt = jwt + Jwt = jwt, + RefreshToken = refreshToken.Value, }; - return (signInResult, res); + } + + private static string ProcessErrorResult(Microsoft.AspNetCore.Identity.SignInResult result) + { + if (result.IsLockedOut) + { + return "Account Locked Out"; + } + + return result.IsNotAllowed ? "Login not allowed" : "Wrong Credentials"; } } } diff --git a/Micro.Auth.Storage/RefreshTokenRepository.cs b/Micro.Auth.Storage/RefreshTokenRepository.cs index 260a696..a5cb4fc 100644 --- a/Micro.Auth.Storage/RefreshTokenRepository.cs +++ b/Micro.Auth.Storage/RefreshTokenRepository.cs @@ -39,6 +39,10 @@ public Task FindById(string id) { return _db.RefreshTokens.AsNoTracking().Where(x => x.Id == id).FirstOrDefaultAsync(); } + private Task FindByValue(string value) + { + return _db.RefreshTokens.AsNoTracking().Where(x => x.Value == value).FirstOrDefaultAsync(); + } public async Task> FindByUser(string userId) { @@ -61,7 +65,7 @@ public Task Delete(string id) public async Task TouchLastUsed(string id) { - var token = await FindById(id); + var token = await FindByValue(id); if (token == null) { throw new RefreshTokenNotFoundException();