JWT Authentication and authorization without using api controller - asp.net

I am trying to make login with JWT authentication. But wherever i find the way of use it always use with api but I do not want to use api i just want to creat just separate controller for login.Kindly tell me how to authorize with jwt and without api.

According to your description,if you want to enable the JWT authentication for MVC, I suggest you could follow this article.
The difference between the JWT authentication for the MVC and Web API is you need store the token at somewhere, since the web api you need to set the token inside the Authorization header for each request.
To solve this issue, you could follow the article which I shared, it store the token inside the session and then it will write a middleware which will read the token from session and then set it at the request header.
The middleware like this.
app.Use(async (context, next) =>
{
var token = context.Session.GetString("Token");
if (!string.IsNullOrEmpty(token))
{
context.Request.Headers.Add("Authorization", "Bearer " + token);
}
await next();
});
For store the token, you could write you own codes and then using the session storage to store the token.
HttpContext.Session.SetString("Token", generatedToken);

Related

Authorization code flow in asp.net core and Is4 - jwt and cookies

I have simply basic solution for asp.net core web app and Is4.
In asp.net core I use addCookies() method, but the is4 returns me jwt token, why there is jwt when I use cookies?
I figure out it when I call
HttpContext.getTokenAsync(openIdconnectparameterNames.idToken)
Here I get jwt.. Can someone explain me why I get JWT if I'm using cookies?
I will try to explain how authentication using OpenId Connect Authorization Code flow is usually implemented for an asp.net core web app.
When an unauthenticated user (no cookie) tries to access your web app, the web app initiates the authorization code flow in order to authenticate the user. During the flow, the user is prompted to log in and then at some point, if login was successful, the identity provider (IdentityServer4) sends an ID token and an access token to the web app as you can also see in the diagram below:
The ID token contains user profile information. This is how the web app knows which user logged in. The access token can be used to get additional user information by calling the User Info Endpoint of Identity Server. Now the web app creates a cookie that contain all necessary user information, so that the next time he tries to access the web app, it won't have to initiate the whole authorization flow again. The web app will be able to identify if user is authenticated by validating the cookie.
The whole id token and access token are saved inside the cookie if you set SaveToken property to true in AddOpenIdConnect options.
services.AddAuthentication(options =>
{
options.DefaultScheme = "Cookies";
options.DefaultChallengeScheme = "oidc";
})
.AddCookie("Cookies")
.AddOpenIdConnect("oidc", options =>
{
//...
// access token is needed to make this request to identity server
options.GetClaimsFromUserInfoEndpoint = true;
options.SaveTokens = true;
});
Then you can read the tokens from cookie using
var accessToken = await HttpContext.GetTokenAsync("access_token");
var idToken = await HttpContext.GetTokenAsync("id_token");
Saving the tokens in the cookie is not necessary and you shouldn't do it if you don't need the tokens anymore after authentication (for example you might need the access token to access an API: https://docs.identityserver.io/en/latest/quickstarts/3_aspnetcore_and_apis.html).
https://auth0.com/docs/get-started/authentication-and-authorization-flow/authorization-code-flow

Got JWT Token from Azure AD B2C but getting 401 error in ASP.NET Core app

I'm implementing Azure AD B2C in a new ASP.NET Core 2.1 app.
I've already created the Azure AD B2C tenant and registered my app, etc.
After I login, I get redirected to the URL I specify and I see the token in the URL but I get an error stating the app requires authentication -- see below:
I saw a few similar posts and what I gather is that the token is automatically validated by the middleware. Is that not so?
What do I need to do at this point?
The code I included in my app are as follows:
In ConfigureServices() method:
services.AddAuthentication(options => {
options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(jwtOptions => {
jwtOptions.Authority = $"https://login.microsoftonline.com/tfp/{Configuration["AzureAdB2C:Tenant"]}/{Configuration["AzureAdB2C:Policy"]}/v2.0/";
jwtOptions.Audience = Configuration["AzureAdB2C:ClientId"];
jwtOptions.Events = new JwtBearerEvents
{
OnAuthenticationFailed = AuthenticationFailed
};
});
In Configure() method in Startup.cs, all I have is app.UseAuthentication();
In my controller, I'm also using [Authorize] to make sure my actions are not open to anonymous users.
What am I missing? How do validate the token and get the claims?
Combining our discussion here as an answer.
The typical approach to this kind of app is that you allow unauthenticated clients to download the HTML, JS, and other static content.
Then the front-end can use MSAL.JS to authenticate the user.
The front-end SPA will get an Id token which tells the front-end who the user is.
MSAL.JS also allows you to get access tokens to call APIs.
It uses hidden iframes + the Implicit Grant flow to do this.
That access token will then need to be attached to requests to the API as a header (Authorization: Bearer token-goes-here).
MSAL.JS will use session or local storage to store the tokens (this is configurable).
So no cookies are used in this setup.
Then the back-end API should authenticate the access token it receives in the header.
What you have there is already sufficient to authenticate the token.
services.AddAuthentication(options => {
options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(jwtOptions => {
jwtOptions.Authority = $"https://login.microsoftonline.com/tfp/{Configuration["AzureAdB2C:Tenant"]}/{Configuration["AzureAdB2C:Policy"]}/v2.0/";
jwtOptions.Audience = Configuration["AzureAdB2C:ClientId"];
jwtOptions.Events = new JwtBearerEvents
{
OnAuthenticationFailed = AuthenticationFailed
};
});
The JWT Bearer authentication handler will load the OpenId Connect metadata document on startup from the authority configured here.
That allows it to get the B2C tenant's public signing keys among other things.
This info allows the handler to then validate access tokens as they come in without interacting with B2C in any way.
It checks the signature is valid, the issuer is valid, and that the audience in the token is what has been configured.
Authorization is of course not handled by the authentication handler, so you must then also check that the calling user actually is allowed to access the resource they are accessing.
The user id is available in the access token.
MSAL.JS may have done some validation on the token as well (I can't remember right now if it did), but doing validation in the front-end is something that can be worked around by anyone with control of the user's browser.
Validation on the API side is the most important piece.

Asp.Net - Jwt Bearer Authentication: Invalid Signature

I obtain an access_token and id_token from AzureAD for my app, which is using OAuth2 with the implicit flow. This is a sample URL where I obtain the tokens:
https://login.microsoftonline.com/my_tenant_id/oauth2/v2.0/authorize?response_type=id_token+token&client_id=my_client_id&state=some_state&redirect_uri=http%3A%2F%2Flocalhost%3A4200%2Fsign-in&scope=openid%20https%3A%2F%2Fgraph.microsoft.com%2Fuser.read&nonce=some_nonce
The scope is openid https://grap.microsoft.com/user.read.
The response_type is id_token+token.
I also have a Asp.Net backend, I want to secure. So I use the Authorize Attribute for my controller and send a token in the header as like this: "Authentication : Bearer THE_TOKEN".
My configuration in Startup.cs looks like this:
app.UseJwtBearerAuthentication(new JwtBearerOptions
{
Authority = string.Format("https://login.microsoftonline.com/{0}/v2.0/",
"d67853c3-db96-4dac-a37b-f2bfb12b42d1"),
Audience = "8422b3fb-5612-4fdd-a90f-707d7218de57"
});
From what I have read, the access token should be used for this, and the id_token should not leave the frontend. But authentication in the backend only works with the id token in my case. The access_token can not be signed Bearer error="invalid_token", error_description="The signature is invalid".
Looking at the access_token in jwt.io, I see the tokens have different audiences and issuers. The access_token for example has this
"aud": "https://graph.microsoft.com",
"iss": "https://sts.windows.net/d67853c3-db96-4dac-a37b-f2bfb12b42d1/",
whereas the id token has this
"aud": "my_client_id",
"iss": "https://login.microsoftonline.com/my_tenant_id/v2.0",
So it seems to me, the access_token was somehow issued for the Graph API. Would be glad if someone could tell me, what i am doing wrong or how I can try to solve my issues.
edit:
It WAS working as intended before when I used the scope openid profile. But due to changes in Azure, this scope is not valid anymore and Microsoft directed me to use the scope mentioned above.
As you mentioned, the access token you requested is for the Microsoft Graph. And the id_token is only for the client to authenticate the user instead of for the resource server.
To protect the web API using the Azure AD V2.0 endpoint, we can acquire the access token for the web API like request below:
https://login.microsoftonline.com/common/oauth2/v2.0/authorize?response_type=token&client_id={client_id}&scope=api://{client_id}/access_as_user&redirect_uri={redirect_uri}
And here is the code using protecting the web API via Azure AD V2.0 endpoint:
public void ConfigureAuth(IAppBuilder app)
{
System.Diagnostics.Trace.TraceWarning("Hello");
var tvps = new TokenValidationParameters
{
// The web app and the service are sharing the same clientId
ValidAudience = clientId,
ValidateIssuer = false,
};
// NOTE: The usual WindowsAzureActiveDirectoryBearerAuthenticaitonMiddleware uses a
// metadata endpoint which is not supported by the v2.0 endpoint. Instead, this
// OpenIdConenctCachingSecurityTokenProvider can be used to fetch & use the OpenIdConnect
// metadata document.
app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions
{
AccessTokenFormat = new JwtFormat(tvps, new OpenIdConnectCachingSecurityTokenProvider("https://login.microsoftonline.com/common/v2.0/.well-known/openid-configuration")),
});
}
}
More detail about protecting the web API via Azure AD V2.0 endpoint, you can refer the document below:
Calling a web API from a .NET web app

How does Identity.GetUserId() finds the user Id?

Question
How does User.Identity.GetUserId() finds the current user's Id?
Does it find the user Id from the Cookies, or does it query the database? Or any other methods?
Problem
For some reason, User.Identity.GetUserId() returns null when I add a valid Bearer Token to my Http request header and send the request to my controller's endpoint:
// MVC Controller Action Method
[Authorize]
public HttpResponseMessage(UserInfoViewModel model)
{
// Request passes the Authorization filter since a valid oauth token
// is attached to the request header.
string userId = User.Identity.GetUserId();
// However, userId is null!
// Other stuff...
}
How does User.Identity.GetUserId() finds the current user's Id?
ClaimTypes.NameIdentifier is the claim used by the function User.Identity.GetUserId()
You would need to add the claim in your authorization code,
identity.AddClaim(ClaimTypes.NameIdentifier, user.Id);
identity is of type ClaimIdentity.
When the user is logged into your app, the server, using ASP.NET Identity, validates your user using DB and creates a valid token that returns to the UI. This token will be valid to its expiration and has inside all information needed to authenticate and authorize the user, including the user's Id. Next calls from client side to server side must be done using this token in the http request header, but server will not call the DB again, because ASP.NET identity knows how to decrypt the token and get all the information of your user.
The use of cookies is only a way to store the token in the client side. As I commented above, you have to send the token on the next requests after the login, so you can store this token in cookies or in Session Storage in your browser.
First, make sure you're not allowing for non-authenticated users.
After that, you want to parse Bearer tokens you have to configure it.
You're going to the need this package Microsoft.Owin.Security.OAuth
And at startup if have to configure ASP.NET Identity to use Bearer Authentication with:
app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions {
// your options;
});
Probably on your StartupAuth.cs file

authenticated access to Firebase REST API within cloud functions

I am trying to access the firebase REST API from a cloud function, using the built-in functions.config().firebase object (my use case is a shallow query).
const { credential } = functions.config().firebase;
credential.getAccessToken().then( ({ access_token }) => {
// use access_token as auth param to query the REST API
});
When I use the returned access_token as the auth parameter in the REST API, I get the could not parse auth token error. Is there a way of generating there a valid auth token without exposing in the config the database secret ?
Many thanks for your help.
Turns out this is a correct way of generating an authentication token, but that with this token, one need to use an access_token param instead of the documented auth one.

Resources