I have a web api connected to a database, which provides access tokens using OpenIddict and the password flow (Resource Owner Password Credentials Grant):
services.AddOpenIddict<TestUser, IdentityRole<Guid>, CompleteContext, Guid>()
.EnableTokenEndpoint("/connect/token")
.AllowPasswordFlow()
.AllowRefreshTokenFlow()
.DisableHttpsRequirement()
.AddEphemeralSigningKey();
The web api has protected actions, which only can be called with a valid access token. This is working fine.
I have a web app which should use the same access tokens for authorization. The user enters his credentials and the web app sends them to the API to get an access token. I thought, that the web app can use this access token for authorization, but I don't now how to set up the middleware in asp.net core.
Background: The web app and the web api should run on different servers and later I want to create mobile applications, which use the web api to access the data. That is why I want to use tokens. I want the web api to be the only project with access ot the database.
Edit more background:
The web app is a mvc 6 app, with standard user functionality: register, login, logout, email confirmation and some interactions with user generated content. All of this content should be stored in a database. Because I may need to add a mobile application later I want to have a separated web api for storing and accessing the data in the database. The only purpose of the web api is handling the data access. The mvc web app should communicate with the web api to get and store the data. The user has to be authenticated to use the web app and the web app must be authenticated to access the web api. There are no third party applications, which made me think of the password flow. I thougt, that the user enters his credentials in the web app to get the access token from the web api. My plan is, that the access token is stored in a cookie, so that the web app can use it to access the web api, if needed. Can I use this access token for the authentication and authorization at the web app too? Maybe something like creating a custom SignInManager
and UserManager
, or give the web app database access and use the standard asp.net identity. Or is there another better solution?
I thought, that the web app can use this access token for authorization, but I don't now how to set up the middleware in asp.net core.
There's nothing in ASP.NET Core that will help you implement a "resource owner password credentials grant" client. Luckily, it's something you can easily do yourself with HttpClient
. Here's how you could do that (note that error handling is left as an exercise):
public async Task<IActionResult> SignIn(string username, string password)
{
if (string.IsNullOrEmpty(username) || string.IsNullOrEmpty(password))
{
return View("MissingCredentials");
}
var request = new HttpRequestMessage(HttpMethod.Post, "http://server.com/connect/token");
request.Content = new FormUrlEncodedContent(new Dictionary<string, string>
{
["client_id"] = "your client_id",
["client_secret"] = "your client_secret",
["grant_type"] = "password",
["username"] = "username",
["password"] = "password"
});
var response = await client.SendAsync(request, notification.Request.CallCancelled);
response.EnsureSuccessStatusCode();
var payload = JObject.Parse(await response.Content.ReadAsStringAsync());
var token = payload.Value<string>("access_token");
if (string.IsNullOrEmpty(token))
{
return View("InvalidCredentials");
}
var identity = new ClaimsIdentity("Cookies");
identity.AddClaim(new Claim("access_token", token));
return SignIn(new ClaimsPrincipal(identity), "Cookies");
}
Alternatively, you could consider using an interactive flow like the authorization code, which would allow you to use the OpenID Connect client middleware developed by the ASP.NET team. You can give this OpenIddict MVC sample a try to understand how it works.