I\'m trying to do authentication with Bearer tokens and owin.
I can issue the token fine using the grant type password
and overriding GrantResour
I'm not sure if this helps but I had a problem with IsAuthenticated coming back false whilst using dependency injection (see SO question here) and it looked to because at the point of injection it hadn't been set by the Owin pipeline.
I overcame it by lazy injecting the Principal. Either way I put together a really basic application (which is linked to in the above) to demonstrate the problem, but it might help you as it shows the Principal being set in the attribute and use of bearer authentication.
I was looking for the same solution, I spent a week or so on this and I left it. Today I started to search again, I found your questions and I was hoping to find an answer.
So I spent the whole day doing nothing other than trying all the possible solutions, merging suggestions with each other, I found some solution but they were long workarounds, to make the long story short here is what I found.
First of all if you need to authenticate the Web site with a custom third party identity provider token you need to have them both using the same machineKey or you need to have them both on the same server.
You need to add the machineKey to the system.web
section as following:
Web.Config
<system.web>
<authentication mode="None" />
<compilation debug="true" targetFramework="4.5" />
<httpRuntime targetFramework="4.5" />
<machineKey validationKey="*****" decryptionKey="***" validation="SHA1" decryption="AES" />
</system.web>
Here is a link to generate a new machineKey :
Now you need to move to the Startup.Auth.cs file where you can find the Startup.cs partial class, you need to define the OAuthBearerOptions
Startup.Auth.cs
public partial class Startup
{
public static OAuthBearerAuthenticationOptions OAuthBearerOptions { get; private set; }
...
public void ConfigureAuth(IAppBuilder app)
{
// Configure the db context, user manager and signin manager to use a single instance per request
app.CreatePerOwinContext(ApplicationDbContext.Create);
app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
OAuthBearerOptions = new OAuthBearerAuthenticationOptions();
app.UseOAuthBearerAuthentication(OAuthBearerOptions);
...
}
}
Replace your Login action inside AccountController with the following:
AccountController.cs
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
{
/*This will depend totally on how you will get access to the identity provider and get your token, this is just a sample of how it would be done*/
/*Get Access Token Start*/
HttpClient httpClient = new HttpClient();
httpClient.BaseAddress = new Uri("https://youridentityproviderbaseurl");
var postData = new List<KeyValuePair<string, string>>();
postData.Add(new KeyValuePair<string, string>("UserName", model.Email));
postData.Add(new KeyValuePair<string, string>("Password", model.Password));
HttpContent content = new FormUrlEncodedContent(postData);
HttpResponseMessage response = await httpClient.PostAsync("yourloginapi", content);
response.EnsureSuccessStatusCode();
string AccessToken = Newtonsoft.Json.JsonConvert.DeserializeObject<string>(await response.Content.ReadAsStringAsync());
/*Get Access Token End*/
If(!string.IsNullOrEmpty(AccessToken))
{
var ticket = Startup.OAuthBearerOptions.AccessTokenFormat.Unprotect(AccessToken);
var id = new ClaimsIdentity(ticket.Identity.Claims, DefaultAuthenticationTypes.ApplicationCookie);
AuthenticationManager.SignIn(new AuthenticationProperties() { IsPersistent = true }, id);
return RedirectToLocal(returnUrl);
}
ModelState.AddModelError("Error", "Invalid Authentication");
return View();
}
The last thing you need to do is to place this line of code in the Global.asax.cs to avoid Anti Forgery exceptions:
Global.asax.cs
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
AntiForgeryConfig.UniqueClaimTypeIdentifier = ClaimTypes.NameIdentifier;
…
}
}
Hope this would work for you.
Well, I have been working on this for some time now and I finally figured out what is wrong and now it is working.
It appears that your Cors enabling code on the GrantResourceOwnerCredentials method is somehow overruling the header from the parameter. So by putting your first line right below your current third you will have your problem solved:
var userManager = context.OwinContext.GetUserManager<ApplicationUserManager>();
IdentityUser user = await userManager.FindAsync(context.UserName, context.Password);
context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { "*" });
So far I haven't dug deeper to understand why this is so, but I believe that by adding the new header entry before getting the userManager somehow corrupts the data that is being sent by the post method on the client, in my case, an angular resource that goes like this:
function userAccount($resource, appSettings) {
return {
registration: $resource(appSettings.serverPath + "/api/Account/Register", null,
{
'registerUser' : { method : 'POST'}
}
),
login : $resource(appSettings.serverPath + "/Token", null,
{
'loginUser': {
method: 'POST',
headers: {
'Content-Type' : 'application/x-www-form-urlencoded'
},
transformRequest: function (data, headersGetter) {
var str = [];
for (var d in data) {
str.push(encodeURIComponent(d) + "=" + encodeURIComponent(data[d]));
}
return str.join("&");
}
}
}
)
}
}
A year since this was posted, and I too experienced the same problem.
As you can see, my bearer token is recognized in the request headers, but my identity is still not be authenticated.
To fix, the short answer is make sure to configure your OAuth middleware before you configure your WebApi middleware (HttpConfiguration).