I am using the VS 2017 Asp.Net Core 2.0 web application template, with the React.js template option.
This gives me a basic MVC + React setup with: 1. a single MVC page that hosts the React application 2. A ClientApp folder for the React application 3. A Rest API to which the React application talks.
By default none of these are authenticated. I want to secure both the MVC page and the REST API.
I have modified the code so that I use cookie authentication for the MVC page, and JWT bearer authentication for the REST API.
For the MVC cookie authentication, I have an MVC login login form. This works fine.
For the REST API authentication, I have added a TokensController that receives a username and login, and generates a JWT token to be used for requests to the REST API. This also works fine when tested from Postman: if user If user tries to access REST API without valid JWT token, user gets 401 response. If users gets token from TokensController and uses that to access REST API, user gets 200 response.
My problem is combining these two. What I would like is that when an unauthenticated user comes to my MVC page, user is redirected to a login form. When submitting that form, user would be authenticated to both the MVC application (getting back a cookie) AND to the REST API (getting back a JWT token).
I tried to achieve this so that instead of using an MVC login page, I would have a React login component, and unauthenticated user would be redirected to that. On submitting the React login form, in the React onSubmit event I would first call TokensController to get JWT token, store that token in browser localStorage, and then submit the form to the MVC controller for the cookie login.
I cannot make MVC redirect to my React login component. Probably some client-side versus server-side routing issue I don't grasp.
In routes.tsx, I am setting my React login component to this route:
<Route path='/login' component={Login} />
In Startup.cs, I have this:
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
// Cookie auth for MVC page that hosts React app
.AddCookie(options =>
{
options.LoginPath = new PathString("/Account/Login");
options.LogoutPath = new PathString("/Account/Logout");
options.Cookie = new CookieBuilder
{
HttpOnly = true,
Name = "OurCookieAuthentication",
Path = "/",
SameSite = SameSiteMode.Lax,
SecurePolicy = CookieSecurePolicy.SameAsRequest
};
options.ExpireTimeSpan = TimeSpan.FromMinutes(30);
options.SlidingExpiration = true;
}
)
// JWT authenticaton for REST API called by React app
.AddJwtBearer(JwtBearerDefaults.AuthenticationScheme, options => {
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateAudience = false,
ValidateIssuer = false,
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("thesecret")),
ValidateLifetime = true,
ClockSkew = TimeSpan.FromMinutes(5)
};
});
;
services.AddMvc()
}
Above, this currently points to my MVC login page, which works fine for the cookie login but does not handle the JWT:
options.LoginPath = new PathString("/Account/Login");
If I change it to this in an attempt to do the redirect to my React login component, it does not work (my React component is not loaded, probably because request goes to "/login" path on the server MVC controller instead of my client React component):
options.LoginPath = new PathString("/login");
Any ideas on how I could best achieve what I'm after?