The next blog series from @Taiseer Joudeh ( http://bitoftech.net/2015/01/21/asp-net-identity-2-with-asp-net-web-api-2-accounts-management/ ) I created a simple WebApi with JWT authentication. I can log in and request my endpoint using a token.
I am trying to change the way the login mechanism works.
Now the user must send his username and password to /oauth/token in order to get an access token, which will be sent with each request to webapi.
I would like to be able to enter the user into the system with a password that will be sent via SMS to the phone number assigned to his account.
It should require two queries on the marker endpoint path. The first one with a single user identifier (login or unique identifier), then the endpoint should check if the user exists, if so, then he must send the password via SMS.
Then the user enters this password into my form, and the second request will be executed using the token endpoint path with the user ID and password.
I read about two-factor authentication ( http://bitoftech.net/2014/10/15/two-factor-authentication-asp-net-web-api-angularjs-google-authenticator/ and other sources), but this requires a user to log in using a username and password, and then to send a second password with SMS.
In my case, I want the user to send only the username and password of SMS.
EDIT: Below the code I tried to create is the starting point, but I don't know how to finish its implementation. I exceeded GrantCustomExtension in OAuthAuthorizationServerProvider
public override async Task GrantCustomExtension(OAuthGrantCustomExtensionContext context) { const string allowedOrigin = "*"; context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { allowedOrigin }); //custom grant_type 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; } //generate one-time password //store it in database //send it to user phone number //return ok message context.Validated(); //return base.GrantCustomExtension(context); }
And here is the part of Startup.cs that is responsible for setting up oAuthAuthorizationServer:
public void ConfigureOAuthTokenGeneration(IAppBuilder app) { app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create); app.CreatePerOwinContext<ApplicationRoleManager>(ApplicationRoleManager.Create); var issuer = ConfigurationManager.AppSettings["Issuer"]; OAuthAuthorizationServerOptions oAuthServerOptions = new OAuthAuthorizationServerOptions() { #if DEBUG AllowInsecureHttp = true, #endif TokenEndpointPath = new PathString("/oauth/token"), AccessTokenExpireTimeSpan = TimeSpan.FromMinutes(1), Provider = new CustomOAuthProvider(), AccessTokenFormat = new CustomJwtFormat(issuer) };
I can send the user type grant_type and find the user in the database, but the hardest part is still missing. I know that I can save this one-time password in the User table, but maybe ASP.Net Identity 2 has a built-in mechanism, I do not want to reinvent the wheel.