This question is continuation of my previous one: ASP.Net Identity 2 login using password from SMS - not using two-factor authentication
I've build my custom OAuthAuthorizationServerProvider to support custom grant_type.
My idea was to create grant_type of sms
that will allow user to generate one-time access code that will be send to his mobile phone and then user as password when sending request with grant_type of password.
Now after generating, storing and sending via SMS that password I'd like to return custom response, not token from my GrantCustomExtension.
public override async Task GrantCustomExtension(OAuthGrantCustomExtensionContext context)
{
const string allowedOrigin = "*";
context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] {allowedOrigin});
if (context.GrantType != "sms")
{
context.SetError("invalid_grant", "unsupported grant_type");
return;
}
var userName = context.Parameters.Get("username");
if (userName == null)
{
context.SetError("invalid_grant", "username is required");
return;
}
var userManager = context.OwinContext.GetUserManager<ApplicationUserManager>();
ApplicationUser user = await userManager.FindByNameAsync(userName);
if (user == null)
{
context.SetError("invalid_grant", "user not found");
return;
}
var generator = new TotpSecurityStampBasedTokenProvider<ApplicationUser, string>();
await userManager.UpdateSecurityStampAsync(user.Id);
var accessCode = await generator.GenerateAsync("SMS", userManager, user);
var accessCodeExpirationTime = TimeSpan.FromMinutes(5);
var result = await userManager.AddAccessCode(user, accessCode, accessCodeExpirationTime);
if(result.Succeeded)
{
Debug.WriteLine("Login code:"+accessCode);
//here I'll send login code to user phone via SMS
}
//return 200 (OK)
//with content type="application/json; charset=utf-8"
//and custom json content {"message":"code send","expires_in":300}
//skip part below
ClaimsIdentity oAuthIdentity = await user.GenerateUserIdentityAsync(userManager, "SMS");
var ticket = new AuthenticationTicket(oAuthIdentity, null);
context.Validated(ticket);
}
How can I stop generating token and return custom response from OAuthAuthorizationServerProvider?
I'm aware of two methods: TokenEndpoint
, TokenEndpointResponse
, but I'd like to override whole response, not just token.
EDIT:
For now I'm creating temporary ClaimsIdentity in GrantCustomExtension
using code below:
var ci = new ClaimsIdentity();
ci.AddClaim(new Claim("message","send"));
ci.AddClaim(new Claim("expires_in", accessCodeExpirationTime.TotalSeconds.ToString(CultureInfo.InvariantCulture)));
context.Validated(ci);
and I'm overriding TokenEndpointResponse
:
public override Task TokenEndpointResponse(OAuthTokenEndpointResponseContext context)
{
if (context.TokenEndpointRequest.GrantType != "sms") return base.TokenEndpointResponse(context);
//clear response containing temporary token.
HttpContext.Current.Response.SuppressContent = true;
return Task.FromResult<object>(null);
}
This has two issues: when calling context.Validated(ci);
I'm saying this is a valid user, but instead I'd like to response information that I've send access code via SMS.
HttpContext.Current.Response.SuppressContent = true;
clears response, but I'd like to return something instead of empty response.
OAuthAuthorizationServerProvider
isn't providing any simple solution for this. I think I'm not the only one who would like to do this kind of mix authentication. – Nimiety