I have a mvc 5 app that uses forms authentication but the real Authentication of user happens using bearer token in web api . I'm adding token details in the cookie so the website is always authenticated. MVC and Web api are in same project. Web api hosted using Owin.
here is my code snippet.
startup.cs
public partial class Startup
{
public void Configuration(IAppBuilder app)
{
//Configure authorization
ConfigureOAuth(app);
//register WebAPI
app.UseWebApi(ConfigureWebApiRoutes());
}
}
startup.auth.cs
// Enable the application to use a cookie to store information for the signed in user
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
LoginPath = new PathString("/Login/Login"),
CookieHttpOnly = true,
//AuthenticationMode = AuthenticationMode.Passive,
CookieName = "YetAnotherTodo.WebApi.Auth",
//#if DEBUG
// CookieSecure = CookieSecureOption.Never
//#endif
});
// Use a cookie to temporarily store information about a user logging in with a third party login provider
app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
OAuthBearerOptions = new OAuthBearerAuthenticationOptions();
// using OAuth authentication server as authentication middle ware and Token Generation
app.UseOAuthAuthorizationServer(new OAuthAuthorizationServerOptions
{
TokenEndpointPath = new PathString("/token"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(1),
Provider = new SimpleAuthorizationServerProvider(),
AuthorizeEndpointPath = new PathString("/api/Account/ExternalLogin"),
#if DEBUG
AllowInsecureHttp = true
#endif
});
app.UseOAuthBearerAuthentication(OAuthBearerOptions);
code in MVC Login Controller
[AllowAnonymous]
[HttpPost]
public async Task<ActionResult> Login(LoginViewModel model, string redirectUrl = null)
{
if (!ModelState.IsValid) return View(model);
try
{
if (string.IsNullOrWhiteSpace(redirectUrl))
{
redirectUrl = "~/Home";
}
var result = await WebApiService.Instance.AuthenticateAsync<LogInResult>(model.UserName, model.Password);
//Let's keep the user authenticated in the MVC webapp.
//By using the AccessToken, we can use User.Identity.Name in the MVC controllers to make API calls.
FormsAuthentication.SetAuthCookie(result.AccessToken, model.RememberMe);
//Create an AuthenticationTicket to generate a cookie used to authenticate against Web API.
//But before we can do that, we need a ClaimsIdentity that can be authenticated in Web API.
var claims = new[]
{
new Claim(ClaimTypes.Name, model.UserName),
//Name is the default name claim type, and UserName is the one known also in Web API.
new Claim(ClaimTypes.NameIdentifier, model.UserName)
//If you want to use User.Identity.GetUserId in Web API, you need a NameIdentifier claim.
};
//Generate a new ClaimsIdentity, using the DefaultAuthenticationTypes.ApplicationCookie authenticationType.
//This also matches what we've set up in Web API.
var claimsIdentity = new ClaimsIdentity(claims,DefaultAuthenticationTypes.ApplicationCookie);
var authProperties = new AuthenticationProperties
{
ExpiresUtc = result.Expires,
IsPersistent = model.RememberMe,
IssuedUtc = result.Issued,
RedirectUri = redirectUrl
};
var authTicket = new AuthenticationTicket(claimsIdentity, authProperties);
//And now it's time to generate the cookie data. This is using the same code that is being used by the CookieAuthenticationMiddleware class in OWIN.
byte[] userData = DataSerializers.Ticket.Serialize(authTicket);
//Protect this user data and add the extra properties. These need to be the same as in Web API!
//byte[] protectedData = MachineKey.Protect(userData, new[] { "Microsoft.Owin.Security.Cookies.CookieAuthenticationMiddleware", DefaultAuthenticationTypes.ApplicationCookie, "v1" });
//base64-encode this data.
string protectedText = TextEncodings.Base64Url.Encode(userData);
//And now, we have the cookie.
Response.SetCookie(new HttpCookie("YetAnotherTodo.WebApi.Auth")
{
HttpOnly = true,
Expires = result.Expires.UtcDateTime,
Value = protectedText
});
Code in my provider that generates token
AuthenticationTicket ticket;
var cookiesIdentity = GenerateCookiesIdentity(context, user, out ticket);
context.Validated(ticket);
context.Request.Context.Authentication.SignIn(cookiesIdentity);
I was able to login and able to get ticket from token server but on subsequent request or redirect to home page after logging in , I'm still getting 401 error.
This is kinda combinations of these two blogs/tutorials : Blog 1 and Blog 2