public IActionResult AuthCodeV2_Grant([FromQuery] AuthCodeV2 input) { if (!ModelState.IsValid) { return(BadRequest(ModelState)); } //clean out cruft from encoding... input.issuer = HttpUtility.UrlDecode(input.issuer); input.client = HttpUtility.UrlDecode(input.client); input.user = HttpUtility.UrlDecode(input.user); input.redirect_uri = HttpUtility.UrlDecode(input.redirect_uri); input.code = HttpUtility.UrlDecode(input.code); input.state = HttpUtility.UrlDecode(input.state); if (!Uri.IsWellFormedUriString(input.redirect_uri, UriKind.Absolute)) { ModelState.AddModelError(MessageType.UriInvalid.ToString(), $"Uri:{input.redirect_uri}"); return(BadRequest(ModelState)); } Guid issuerID; tbl_Issuer issuer; //check if identifier is guid. resolve to guid if not. if (Guid.TryParse(input.issuer, out issuerID)) { issuer = uow.Issuers.Get(x => x.Id == issuerID).SingleOrDefault(); } else { issuer = uow.Issuers.Get(x => x.Name == input.issuer).SingleOrDefault(); } if (issuer == null) { ModelState.AddModelError(MessageType.IssuerNotFound.ToString(), $"Issuer:{input.issuer}"); return(NotFound(ModelState)); } else if (!issuer.IsEnabled) { ModelState.AddModelError(MessageType.IssuerInvalid.ToString(), $"Issuer:{issuer.Id}"); return(BadRequest(ModelState)); } Guid userID; tbl_User user; //check if identifier is guid. resolve to guid if not. if (Guid.TryParse(input.user, out userID)) { user = uow.Users.Get(x => x.Id == userID).SingleOrDefault(); } else { user = uow.Users.Get(x => x.UserName == input.user).SingleOrDefault(); } if (user == null) { ModelState.AddModelError(MessageType.UserNotFound.ToString(), $"User:{input.user}"); return(NotFound(ModelState)); } //check that user is confirmed... //check that user is not locked... else if (uow.Users.IsLockedOut(user) || !user.EmailConfirmed || !user.PasswordConfirmed) { ModelState.AddModelError(MessageType.UserInvalid.ToString(), $"User:{user.Id}"); return(BadRequest(ModelState)); } var audienceList = uow.Audiences.Get(QueryExpressionFactory.GetQueryExpression <tbl_Audience>() .Where(x => x.tbl_Roles.Any(y => y.tbl_UserRoles.Any(z => z.UserId == user.Id))).ToLambda()); var audiences = new List <tbl_Audience>(); //check if client is single, multiple or undefined... if (string.IsNullOrEmpty(input.client)) { audiences = uow.Audiences.Get(x => audienceList.Contains(x) && x.IsLockedOut == false).ToList(); } else { foreach (string entry in input.client.Split(",")) { Guid audienceID; tbl_Audience audience; //check if identifier is guid. resolve to guid if not. if (Guid.TryParse(entry.Trim(), out audienceID)) { audience = uow.Audiences.Get(x => x.Id == audienceID, y => y.Include(z => z.tbl_Urls)).SingleOrDefault(); } else { audience = uow.Audiences.Get(x => x.Name == entry.Trim(), y => y.Include(z => z.tbl_Urls)).SingleOrDefault(); } if (audience == null) { ModelState.AddModelError(MessageType.AudienceNotFound.ToString(), $"Audience:{input.client}"); return(NotFound(ModelState)); } else if (audience.IsLockedOut || !audienceList.Contains(audience)) { ModelState.AddModelError(MessageType.AudienceInvalid.ToString(), $"Audience:{audience.Id}"); return(BadRequest(ModelState)); } audiences.Add(audience); } } if (audiences.Count == 0) { ModelState.AddModelError(MessageType.AudienceNotFound.ToString(), $"Audience:None"); return(BadRequest(ModelState)); } //check if client uri is valid... var redirect = new Uri(input.redirect_uri); foreach (var entry in audiences) { if (!entry.tbl_Urls.Where(x => x.UrlHost == null && x.UrlPath == redirect.AbsolutePath).Any() && !entry.tbl_Urls.Where(x => new Uri(x.UrlHost + x.UrlPath).AbsoluteUri == redirect.AbsoluteUri).Any()) { ModelState.AddModelError(MessageType.UriInvalid.ToString(), $"Uri:{input.redirect_uri}"); return(BadRequest(ModelState)); } } //check if state is valid... var state = uow.States.Get(x => x.StateValue == input.state && x.ValidFromUtc <DateTime.UtcNow && x.ValidToUtc> DateTime.UtcNow && x.StateType == ConsumerType.User.ToString()).SingleOrDefault(); if (state == null) { ModelState.AddModelError(MessageType.StateNotFound.ToString(), $"User code:{input.state}"); return(BadRequest(ModelState)); } //check that payload can be decrypted and validated... if (!new PasswordTokenFactory(uow.InstanceType.ToString()).Validate(user.SecurityStamp, input.code, user.Id.ToString(), user.SecurityStamp)) { uow.AuthActivity.Create( map.Map <tbl_AuthActivity>(new AuthActivityV1() { UserId = user.Id, LoginType = GrantFlowType.AuthorizationCodeV2.ToString(), LoginOutcome = GrantFlowResultType.Failure.ToString(), })); uow.Commit(); ModelState.AddModelError(MessageType.TokenInvalid.ToString(), $"Token:{input.code}"); return(BadRequest(ModelState)); } var ac_claims = uow.Users.GenerateAccessClaims(issuer, user); var ac = auth.ResourceOwnerPassword(issuer.Name, issuer.IssuerKey, conf["IdentityTenant:Salt"], audiences.Select(x => x.Name).ToList(), ac_claims); uow.AuthActivity.Create( map.Map <tbl_AuthActivity>(new AuthActivityV1() { UserId = user.Id, LoginType = GrantFlowType.AuthorizationCodeV2.ToString(), LoginOutcome = GrantFlowResultType.Success.ToString(), })); var rt_claims = uow.Users.GenerateRefreshClaims(issuer, user); var rt = auth.ResourceOwnerPassword(issuer.Name, issuer.IssuerKey, conf["IdentityTenant:Salt"], audiences.Select(x => x.Name).ToList(), rt_claims); uow.Refreshes.Create( map.Map <tbl_Refresh>(new RefreshV1() { IssuerId = issuer.Id, UserId = user.Id, RefreshType = ConsumerType.User.ToString(), RefreshValue = rt.RawData, ValidFromUtc = rt.ValidFrom, ValidToUtc = rt.ValidTo, })); uow.AuthActivity.Create( map.Map <tbl_AuthActivity>(new AuthActivityV1() { UserId = user.Id, LoginType = GrantFlowType.RefreshTokenV2.ToString(), LoginOutcome = GrantFlowResultType.Success.ToString(), })); uow.Commit(); var result = new UserJwtV2() { token_type = "bearer", access_token = ac.RawData, refresh_token = rt.RawData, user = user.UserName, client = audiences.Select(x => x.Name).ToList(), issuer = issuer.Name + ":" + conf["IdentityTenant:Salt"], expires_in = (int)(new DateTimeOffset(ac.ValidTo).Subtract(DateTime.UtcNow)).TotalSeconds, }; return(Ok(result)); }
public IActionResult ResourceOwnerV2_Grant([FromForm] ResourceOwnerV2 input) { if (!ModelState.IsValid) { return(BadRequest(ModelState)); } Guid issuerID; tbl_Issuer issuer; //check if identifier is guid. resolve to guid if not. if (Guid.TryParse(input.issuer, out issuerID)) { issuer = uow.Issuers.Get(x => x.Id == issuerID).SingleOrDefault(); } else { issuer = uow.Issuers.Get(x => x.Name == input.issuer).SingleOrDefault(); } if (issuer == null) { ModelState.AddModelError(MessageType.IssuerNotFound.ToString(), $"Issuer:{input.issuer}"); return(NotFound(ModelState)); } else if (!issuer.IsEnabled) { ModelState.AddModelError(MessageType.IssuerInvalid.ToString(), $"Issuer:{issuer.Id}"); return(BadRequest(ModelState)); } Guid userID; tbl_User user; //check if identifier is guid. resolve to guid if not. if (Guid.TryParse(input.user, out userID)) { user = uow.Users.Get(x => x.Id == userID).SingleOrDefault(); } else { user = uow.Users.Get(x => x.UserName == input.user).SingleOrDefault(); } if (user == null) { ModelState.AddModelError(MessageType.UserNotFound.ToString(), $"User:{input.user}"); return(NotFound(ModelState)); } //check that user is confirmed... //check that user is not locked... else if (uow.Users.IsLockedOut(user) || !user.EmailConfirmed || !user.PasswordConfirmed) { ModelState.AddModelError(MessageType.UserInvalid.ToString(), $"User:{user.Id}"); return(BadRequest(ModelState)); } var audienceList = uow.Audiences.Get(QueryExpressionFactory.GetQueryExpression <tbl_Audience>() .Where(x => x.tbl_Roles.Any(y => y.tbl_UserRoles.Any(z => z.UserId == user.Id))).ToLambda()); var audiences = new List <tbl_Audience>(); //check if client is single, multiple or undefined... if (string.IsNullOrEmpty(input.client)) { audiences = uow.Audiences.Get(x => audienceList.Contains(x) && x.IsLockedOut == false).ToList(); } else { foreach (string entry in input.client.Split(",")) { Guid audienceID; tbl_Audience audience; //check if identifier is guid. resolve to guid if not. if (Guid.TryParse(entry.Trim(), out audienceID)) { audience = uow.Audiences.Get(x => x.Id == audienceID).SingleOrDefault(); } else { audience = uow.Audiences.Get(x => x.Name == entry.Trim()).SingleOrDefault(); } if (audience == null) { ModelState.AddModelError(MessageType.AudienceNotFound.ToString(), $"Audience:{entry}"); return(NotFound(ModelState)); } else if (audience.IsLockedOut || !audienceList.Contains(audience)) { ModelState.AddModelError(MessageType.AudienceInvalid.ToString(), $"Audience:{audience.Id}"); return(BadRequest(ModelState)); } audiences.Add(audience); } } if (audiences.Count == 0) { ModelState.AddModelError(MessageType.AudienceNotFound.ToString(), $"Audience:None"); return(BadRequest(ModelState)); } var logins = uow.Logins.Get(QueryExpressionFactory.GetQueryExpression <tbl_Login>() .Where(x => x.tbl_UserLogins.Any(y => y.UserId == user.Id)).ToLambda()); switch (uow.InstanceType) { case InstanceContext.DeployedOrLocal: case InstanceContext.End2EndTest: { //check if login provider is local... if (logins.Where(x => x.Name.Equals(DefaultConstants.LoginName, StringComparison.OrdinalIgnoreCase)).Any()) { //check that password is valid... if (!PBKDF2.Validate(user.PasswordHashPBKDF2, input.password)) { uow.AuthActivity.Create( map.Map <tbl_AuthActivity>(new AuthActivityV1() { UserId = user.Id, LoginType = GrantFlowType.ResourceOwnerPasswordV2.ToString(), LoginOutcome = GrantFlowResultType.Failure.ToString(), })); uow.Commit(); ModelState.AddModelError(MessageType.UserInvalid.ToString(), $"User:{user.Id}"); return(BadRequest(ModelState)); } } else { ModelState.AddModelError(MessageType.LoginNotFound.ToString(), $"No login for user:{user.Id}"); return(NotFound(ModelState)); } } break; case InstanceContext.SystemTest: case InstanceContext.IntegrationTest: { //check if login provider is local or test... if (logins.Where(x => x.Name.Equals(DefaultConstants.LoginName, StringComparison.OrdinalIgnoreCase)).Any() || logins.Where(x => x.Name.StartsWith(TestDefaultConstants.LoginName, StringComparison.OrdinalIgnoreCase)).Any()) { //check that password is valid... if (!PBKDF2.Validate(user.PasswordHashPBKDF2, input.password)) { uow.AuthActivity.Create( map.Map <tbl_AuthActivity>(new AuthActivityV1() { UserId = user.Id, LoginType = GrantFlowType.ResourceOwnerPasswordV2.ToString(), LoginOutcome = GrantFlowResultType.Failure.ToString(), })); uow.Commit(); ModelState.AddModelError(MessageType.UserInvalid.ToString(), $"User:{user.Id}"); return(BadRequest(ModelState)); } } else { ModelState.AddModelError(MessageType.LoginNotFound.ToString(), $"No login for user:{user.Id}"); return(NotFound(ModelState)); } } break; default: throw new NotImplementedException(); } var rop_claims = uow.Users.GenerateAccessClaims(issuer, user); var rop = auth.ResourceOwnerPassword(issuer.Name, issuer.IssuerKey, conf["IdentityTenant:Salt"], audiences.Select(x => x.Name).ToList(), rop_claims); uow.AuthActivity.Create( map.Map <tbl_AuthActivity>(new AuthActivityV1() { UserId = user.Id, LoginType = GrantFlowType.ResourceOwnerPasswordV2.ToString(), LoginOutcome = GrantFlowResultType.Success.ToString(), })); var rt_claims = uow.Users.GenerateRefreshClaims(issuer, user); var rt = auth.ResourceOwnerPassword(issuer.Name, issuer.IssuerKey, conf["IdentityTenant:Salt"], audiences.Select(x => x.Name).ToList(), rt_claims); uow.Refreshes.Create( map.Map <tbl_Refresh>(new RefreshV1() { IssuerId = issuer.Id, UserId = user.Id, RefreshType = ConsumerType.User.ToString(), RefreshValue = rt.RawData, IssuedUtc = rt.ValidFrom, ValidFromUtc = rt.ValidFrom, ValidToUtc = rt.ValidTo, })); uow.AuthActivity.Create( map.Map <tbl_AuthActivity>(new AuthActivityV1() { UserId = user.Id, LoginType = GrantFlowType.RefreshTokenV2.ToString(), LoginOutcome = GrantFlowResultType.Success.ToString(), })); uow.Commit(); var result = new UserJwtV2() { token_type = "bearer", access_token = rop.RawData, refresh_token = rt.RawData, user = user.UserName, client = audiences.Select(x => x.Name).ToList(), issuer = issuer.Name + ":" + conf["IdentityTenant:Salt"], expires_in = (int)(new DateTimeOffset(rop.ValidTo).Subtract(DateTime.UtcNow)).TotalSeconds, }; return(Ok(result)); }
public IActionResult ResourceOwnerV2_Refresh([FromForm] RefreshTokenV2 input) { if (!ModelState.IsValid) { return(BadRequest(ModelState)); } var refresh = uow.Refreshes.Get(QueryExpressionFactory.GetQueryExpression <tbl_Refresh>() .Where(x => x.RefreshValue == input.refresh_token).ToLambda()).SingleOrDefault(); if (refresh == null) { ModelState.AddModelError(MessageType.TokenInvalid.ToString(), $"Token:{input.refresh_token}"); return(NotFound(ModelState)); } else if (!string.Equals(refresh.RefreshType, ConsumerType.User.ToString(), StringComparison.OrdinalIgnoreCase) || (refresh.ValidFromUtc >= DateTime.UtcNow || refresh.ValidToUtc <= DateTime.UtcNow)) { ModelState.AddModelError(MessageType.TokenInvalid.ToString(), $"Token:{input.refresh_token}"); return(BadRequest(ModelState)); } Guid issuerID; tbl_Issuer issuer; //check if identifier is guid. resolve to guid if not. if (Guid.TryParse(input.issuer, out issuerID)) { issuer = uow.Issuers.Get(x => x.Id == issuerID).SingleOrDefault(); } else { issuer = uow.Issuers.Get(x => x.Name == input.issuer).SingleOrDefault(); } if (issuer == null) { ModelState.AddModelError(MessageType.IssuerNotFound.ToString(), $"Issuer:{input.issuer}"); return(NotFound(ModelState)); } else if (!issuer.IsEnabled) { ModelState.AddModelError(MessageType.IssuerInvalid.ToString(), $"Issuer:{issuer.Id}"); return(BadRequest(ModelState)); } var user = uow.Users.Get(x => x.Id == refresh.UserId).SingleOrDefault(); //check that user exists... if (user == null) { ModelState.AddModelError(MessageType.UserNotFound.ToString(), $"User:{refresh.UserId}"); return(NotFound(ModelState)); } //check that user is not locked... else if (uow.Users.IsLockedOut(user) || !user.EmailConfirmed || !user.PasswordConfirmed) { ModelState.AddModelError(MessageType.UserInvalid.ToString(), $"User:{user.Id}"); return(BadRequest(ModelState)); } var clientList = uow.Audiences.Get(QueryExpressionFactory.GetQueryExpression <tbl_Audience>() .Where(x => x.tbl_Roles.Any(y => y.tbl_UserRoles.Any(z => z.UserId == user.Id))).ToLambda()); var audiences = new List <tbl_Audience>(); //check if client is single, multiple or undefined... if (string.IsNullOrEmpty(input.client)) { audiences = uow.Audiences.Get(x => clientList.Contains(x) && x.IsLockedOut == false).ToList(); } else { foreach (string entry in input.client.Split(",")) { Guid audienceID; tbl_Audience audience; //check if identifier is guid. resolve to guid if not. if (Guid.TryParse(entry.Trim(), out audienceID)) { audience = uow.Audiences.Get(x => x.Id == audienceID).SingleOrDefault(); } else { audience = uow.Audiences.Get(x => x.Name == entry.Trim()).SingleOrDefault(); } if (audience == null) { ModelState.AddModelError(MessageType.AudienceNotFound.ToString(), $"Audience:{entry}"); return(NotFound(ModelState)); } else if (audience.IsLockedOut || !clientList.Contains(audience)) { ModelState.AddModelError(MessageType.AudienceInvalid.ToString(), $"Audience:{audience.Id}"); return(BadRequest(ModelState)); } audiences.Add(audience); } } if (audiences.Count == 0) { ModelState.AddModelError(MessageType.AudienceNotFound.ToString(), $"Audience:None"); return(BadRequest(ModelState)); } var rop_claims = uow.Users.GenerateAccessClaims(issuer, user); var rop = auth.ResourceOwnerPassword(issuer.Name, issuer.IssuerKey, conf["IdentityTenant:Salt"], audiences.Select(x => x.Name).ToList(), rop_claims); var rt_claims = uow.Users.GenerateRefreshClaims(issuer, user); var rt = auth.ResourceOwnerPassword(issuer.Name, issuer.IssuerKey, conf["IdentityTenant:Salt"], audiences.Select(x => x.Name).ToList(), rt_claims); uow.Refreshes.Create( map.Map <tbl_Refresh>(new RefreshV1() { IssuerId = issuer.Id, UserId = user.Id, RefreshType = ConsumerType.User.ToString(), RefreshValue = rt.RawData, IssuedUtc = rt.ValidFrom, ValidFromUtc = rt.ValidFrom, ValidToUtc = rt.ValidTo, })); uow.AuthActivity.Create( map.Map <tbl_AuthActivity>(new AuthActivityV1() { UserId = user.Id, LoginType = GrantFlowType.RefreshTokenV2.ToString(), LoginOutcome = GrantFlowResultType.Success.ToString(), })); uow.Commit(); var result = new UserJwtV2() { token_type = "bearer", access_token = rop.RawData, refresh_token = rt.RawData, user = user.UserName, client = audiences.Select(x => x.Name).ToList(), issuer = issuer.Name + ":" + conf["IdentityTenant:Salt"], expires_in = (int)(new DateTimeOffset(rop.ValidTo).Subtract(DateTime.UtcNow)).TotalSeconds, }; return(Ok(result)); }
public IActionResult DeviceCodeV2_Grant([FromForm] DeviceCodeV2 input) { if (!ModelState.IsValid) { return(BadRequest(ModelState)); } Guid issuerID; tbl_Issuer issuer; //check if identifier is guid. resolve to guid if not. if (Guid.TryParse(input.issuer, out issuerID)) { issuer = uow.Issuers.Get(x => x.Id == issuerID).SingleOrDefault(); } else { issuer = uow.Issuers.Get(x => x.Name == input.issuer).SingleOrDefault(); } if (issuer == null) { ModelState.AddModelError(MessageType.IssuerNotFound.ToString(), $"Issuer:{input.issuer}"); return(NotFound(ModelState)); } else if (!issuer.IsEnabled) { ModelState.AddModelError(MessageType.IssuerInvalid.ToString(), $"Issuer:{issuer.Id}"); return(BadRequest(ModelState)); } Guid audienceID; tbl_Audience audience; //check if identifier is guid. resolve to guid if not. if (Guid.TryParse(input.client, out audienceID)) { audience = uow.Audiences.Get(x => x.Id == audienceID).SingleOrDefault(); } else { audience = uow.Audiences.Get(x => x.Name == input.client).SingleOrDefault(); } if (audience == null) { ModelState.AddModelError(MessageType.AudienceNotFound.ToString(), $"Audience:{input.client}"); return(NotFound(ModelState)); } else if (audience.IsLockedOut) { ModelState.AddModelError(MessageType.AudienceInvalid.ToString(), $"Audience:{audience.Id}"); return(BadRequest(ModelState)); } var polling = uow.Settings.Get(x => x.IssuerId == issuer.Id && x.AudienceId == null && x.UserId == null && x.ConfigKey == SettingsConstants.PollingMax).Single(); //check if state is valid... var state = uow.States.Get(x => x.StateValue == input.device_code && x.StateType == ConsumerType.Device.ToString() && x.ValidFromUtc <DateTime.UtcNow && x.ValidToUtc> DateTime.UtcNow).SingleOrDefault(); if (state == null || state.StateConsume == true) { ModelState.AddModelError(MessageType.StateInvalid.ToString(), $"Device code:{input.device_code}"); return(BadRequest(ModelState)); } //check if device is polling too frequently... else if (uint.Parse(polling.ConfigValue) <= (state.LastPollingUtc.Subtract(DateTime.UtcNow)).TotalSeconds) { state.LastPollingUtc = DateTime.UtcNow; state.StateConsume = false; uow.States.Update(state); uow.Commit(); ModelState.AddModelError(MessageType.StateSlowDown.ToString(), $"Device code:{input.device_code}"); return(BadRequest(ModelState)); } //check if device has been approved/denied... if (!state.StateDecision.HasValue) { ModelState.AddModelError(MessageType.StatePending.ToString(), $"Device code:{input.device_code}"); return(BadRequest(ModelState)); } else if (state.StateDecision.HasValue && !state.StateDecision.Value) { ModelState.AddModelError(MessageType.StateDenied.ToString(), $"Device code:{input.device_code}"); return(BadRequest(ModelState)); } var user = uow.Users.Get(x => x.Id == state.UserId).SingleOrDefault(); if (user == null) { ModelState.AddModelError(MessageType.UserNotFound.ToString(), $"User:{state.UserId}"); return(NotFound(ModelState)); } //check that user is confirmed... //check that user is not locked... else if (uow.Users.IsLockedOut(user) || !user.EmailConfirmed || !user.PasswordConfirmed) { ModelState.AddModelError(MessageType.UserInvalid.ToString(), $"User:{user.Id}"); return(BadRequest(ModelState)); } if (!new TimeBasedTokenFactory(8, 10).Validate(user.SecurityStamp, input.user_code, user.Id.ToString())) { uow.AuthActivity.Create( map.Map <tbl_AuthActivity>(new AuthActivityV1() { UserId = user.Id, LoginType = GrantFlowType.DeviceCodeV2.ToString(), LoginOutcome = GrantFlowResultType.Failure.ToString(), })); uow.Commit(); ModelState.AddModelError(MessageType.TokenInvalid.ToString(), $"Token:{input.user_code}"); return(BadRequest(ModelState)); } //no reuse of state after this... state.LastPollingUtc = DateTime.UtcNow; state.StateConsume = true; //adjust state... uow.States.Update(state); var dc_claims = uow.Users.GenerateAccessClaims(issuer, user); var dc = auth.ResourceOwnerPassword(issuer.Name, issuer.IssuerKey, conf["IdentityTenant:Salt"], new List <string>() { audience.Name }, dc_claims); uow.AuthActivity.Create( map.Map <tbl_AuthActivity>(new AuthActivityV1() { UserId = user.Id, LoginType = GrantFlowType.DeviceCodeV2.ToString(), LoginOutcome = GrantFlowResultType.Success.ToString(), })); var rt_claims = uow.Users.GenerateRefreshClaims(issuer, user); var rt = auth.ResourceOwnerPassword(issuer.Name, issuer.IssuerKey, conf["IdentityTenant:Salt"], new List <string>() { audience.Name }, rt_claims); uow.Refreshes.Create( map.Map <tbl_Refresh>(new RefreshV1() { IssuerId = issuer.Id, UserId = user.Id, RefreshType = ConsumerType.User.ToString(), RefreshValue = rt.RawData, ValidFromUtc = rt.ValidFrom, ValidToUtc = rt.ValidTo, })); uow.AuthActivity.Create( map.Map <tbl_AuthActivity>(new AuthActivityV1() { UserId = user.Id, LoginType = GrantFlowType.RefreshTokenV2.ToString(), LoginOutcome = GrantFlowResultType.Success.ToString(), })); uow.Commit(); var result = new UserJwtV2() { token_type = "bearer", access_token = dc.RawData, refresh_token = rt.RawData, user = user.UserName, client = new List <string>() { audience.Name }, issuer = issuer.Name + ":" + conf["IdentityTenant:Salt"], expires_in = (int)(new DateTimeOffset(dc.ValidTo).Subtract(DateTime.UtcNow)).TotalSeconds, }; return(Ok(result)); }