I have this config in IdentityServer:
public static IEnumerable<ApiResource> ApiResources =>
new ApiResource[]
{
new ApiResource
{
Name = "MyApi"
}
};
and this jwt configuration on the ASP.NET Core web API:
services.AddAuthentication("Bearer")
.AddJwtBearer("Bearer", options =>
{
//identity server
options.Authority = "https://localhost:5001";
//access token recepient
options.Audience = "https://localhost:5001/resources";
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateAudience = true,
ValidateLifetime = true,
};
});
I'm expecting that the Web API authentication won't accept the token from IdentityServer because the Web API JwtBearerOption.Audience is not equal to "MyApi". But in my config the Audience is only validated if the audience is set to "https://localhost:5001/resources" and will invalidate if I set it to "MyApi"
IdentityServer4 documentation about related to my question.
To get MyApi into the list of audiences you need to define an ApiScope as will in IdentityServer4 (v4.0x)
See this articles for more details
Related
I have added Auth to my swagger UI and at the same time I have also added token through Postman. But every time I try to add or post something to my services. Then it comes up and tells 401 error.
But on the other hand, I remove the Auth part. Then I have no problems posting or adding anything to the database.
I have try this here.
builder.Services.AddSwaggerGen(opt =>
{
opt.SwaggerDoc("v1", new OpenApiInfo { Title = "MyAPI", Version = "v1" });
opt.AddSecurityDefinition("Bearer", //Name the security scheme
new OpenApiSecurityScheme
{
Description = "JWT Authorization header using the Bearer scheme.",
Type = SecuritySchemeType.Http, //We set the scheme type to http since we're using bearer authentication
Scheme = JwtBearerDefaults.AuthenticationScheme //The name of the HTTP Authorization scheme to be used in the Authorization header. In this case "bearer".
});
opt.AddSecurityRequirement(new OpenApiSecurityRequirement{
{
new OpenApiSecurityScheme{
Reference = new OpenApiReference{
Id = JwtBearerDefaults.AuthenticationScheme, //The name of the previously defined security scheme.
Type = ReferenceType.SecurityScheme
}
},new List<string>()
}
});
});
builder.Services
.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(r =>
{
r.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = false,
ValidateAudience = false,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(token.ToString())),
ClockSkew = TimeSpan.Zero
};
});
builder.Services.AddAuthorization(r =>
{
r.AddPolicy("adminAccessData", p => p.RequireClaim("role", "Admin"));
});
When I try to post or look like a controller, I have this piece up at the top of the controller.
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme, Policy = "Admin")]
What I am trying to do. it is that I only want to post or leave something in the database when I am Admin. I have been assigned a role as "Admin" on my Claims when I log in to the site.
I have inherited an ASP.NET Core 5 MVC application that has integrated the authentication of the users with a third-party identity server, WSO2.
The authentication is working fine, but I'm not able to understand how to retrieve the username of the user that has logged in.
Here is the code:
Startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddSession();
services.AddControllersWithViews();
services.AddTransient<IUserRepository, UserRepository>();
services.AddTransient<ITokenService, TokenService>();
services.AddAuthentication(auth =>
{
auth.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
//auth.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ValidIssuer = Configuration["Jwt:Issuer"],
ValidAudience = Configuration["Jwt:Issuer"],
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["Jwt:Key"]))
};
});
services.AddHttpClient();
}
in the controller I have added:
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme, Roles = "Administrator,Supervisor")]
Is the name and roles found in the JWT token?
If, so then the issue is that OpenIDConnect and Microsoft do not agree about what the name of the 'name' claim should be.
To address this, you need to tell AddJwtBearer, which claim is the 'name' and 'role' claim using:
.AddMyJwtBearer(opt =>
{
...
opt.TokenValidationParameters.RoleClaimType = "roles";
opt.TokenValidationParameters.NameClaimType = "name";
I have an application behind an SAML Service Provider. That means, the SP does authentication for me and I get user data in HTTP request headers (like SP_USER_NAME or SP_USER_ROLE). For each endpoint, I would like to authorize users according to roles, and show some error if they have insufficient permissions.
I looked at policy-based authorization in the docs, but that seems a bit overkill for checking a header.
How do I authorize in a simple way, based on a specific header? Plese note that I develop in .NET Core 3.1
Hey I have solution for this please refer below point
first of all you need to add authentication. public void ConfigureServices(IServiceCollection services)
services.AddSession();
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = >JwtBearerDefaults.AuthenticationScheme;
options.DefaultAuthenticateScheme = >JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
})
// Adding Jwt Bearer
.AddJwtBearer(options =>
{
options.SaveToken = true;
options.RequireHttpsMetadata = false;
options.TokenValidationParameters = new TokenValidationParameters()
{
ValidateIssuer = true,
ValidateAudience = true,
ValidAudience = Configuration["JWTConfig:ValidAudience"],
ValidIssuer = Configuration["JWTConfig:ValidIssuer"],
IssuerSigningKey = new >SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["JWTConfig:Secret"]))
};
});
After that you have to Use Session for storing authentication token and in this token you have to encrypt token combination of role list whatever role want to pass for the authorization.
Here i have used JWT Bearer token
Using this session you have to configure in public void Configure(IApplicationBuilder app, IWebHostEnvironment env)startup.cs file for use header authentication.
app.UseSession();
app.Use(async (context, next) =>
{
var token = context.Session.GetString("Token");
if (!string.IsNullOrEmpty(token))
{
context.Request.Headers.Add("Authorization", "Bearer " + token);
}
await next();
});
then after you you have to add in your controller
[Authorize(Roles = "Employee,Student")]
public ActionResult Leave()
{
// your code here
}
I need the Authorize attribute in our Controller can accept two different tokens.
One token, is provided from one private ADFS, and other token is provided from AzureAd.
Several Ionic clients go to over ADFS, other Ionic clients go to over Azure AD
My dev scenario: ASP.NET Core 2.2 Web API
My actual startup.cs (abbreviated)
ConfigureService()
{
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer((options =>
{
options.Audience = Configuration["Adfs:Audience"];
options.Authority = Configuration["Adfs:Issuer"];
options.SaveToken = true;
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = false
};
}));
}
I need here the other Authentication with AzureAD. How?
The Configure method of Startup.cs
Configure(…)
{
app.UseAuthentication()
}
With this code, only can access the ADFS Token and this users, can obtains result from the controllers. However, the AzureAD user's can't obtain access
I don't know how make this code for double token authorization, and our controllers can response if one token is from ADFS or other token is from AzureAD
You can set multiple JWT Bearer Authentication with different schema name :
services.AddAuthentication()
.AddJwtBearer("ADFS",options =>
{
options.Audience = Configuration["Adfs:Audience"];
options.Authority = Configuration["Adfs:Issuer"];
options.SaveToken = true;
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = false
};
})
.AddJwtBearer("AAD", options =>
{
//AAD jwt validation configuration
});
If you want to make your controller/action to accept two jwt tokens , tokens from AAD or ADFS are ok to access your controller/action , you can make a policy to let both the AAD and ADFS authentication schemes tried to authenticate the request :
services
.AddAuthorization(options =>
{
options.DefaultPolicy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.AddAuthenticationSchemes("AAD", "ADFS")
.Build();
});
In addition , if you want to know which schema the token is from , you can check the particular claim in user's identity , or directly add authentication schema value to user claims in events :
options.Events = new Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerEvents
{
OnTokenValidated = (context) =>
{
var claimsIdentity = (ClaimsIdentity)context.Principal.Identity;
//add your custom claims here
claimsIdentity.AddClaim(new Claim("schema", "AAD"));
return Task.FromResult(0);
}
};
And get in action after authentication :
var result = User.Claims.Where(c=>c.Type=="schema").FirstOrDefault().Value;
I'm using ASP.NET Core 2.1 and Auth0.
When I try to retrieve the acces_token to access my own API I use
string accessToken = await HttpContext.GetTokenAsync("access_token");
The strange thing is when I paste the token on https://jwt.io/ it shows that an audience has been added. The thing is that two audiences are not allowed and so the token is not valid. The audience that is added ends with /userinfo
Can someone please explain why there are two audiences in my acces token?
I use the following code in ConfigureServices
// Add authentication services
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = CookieAuthenticationDefaults.AuthenticationScheme;
})
.AddCookie()
.AddOpenIdConnect("Auth0", options =>
{
// Set the authority to your Auth0 domain
options.Authority = $"https://{Configuration["Auth0:Domain"]}";
// Configure the Auth0 Client ID and Client Secret
options.ClientId = Configuration["Auth0:ClientId"];
options.ClientSecret = Configuration["Auth0:ClientSecret"];
// Set response type to code
options.ResponseType = "code";
// Configure the scope
options.Scope.Clear();
options.Scope.Add("openid");
// Set the callback path, so Auth0 will call back to http://localhost:5000/signin-auth0
// Also ensure that you have added the URL as an Allowed Callback URL in your Auth0 dashboard
options.CallbackPath = new PathString("/signin-auth0");
// Configure the Claims Issuer to be Auth0
options.ClaimsIssuer = "Auth0";
// Saves tokens to the AuthenticationProperties
options.SaveTokens = true;
options.Events = new OpenIdConnectEvents
{
// handle the logout redirection
OnRedirectToIdentityProviderForSignOut = (context) =>
{
var logoutUri = $"https://{Configuration["Auth0:Domain"]}/v2/logout?client_id={Configuration["Auth0:ClientId"]}";
var postLogoutUri = context.Properties.RedirectUri;
if (!string.IsNullOrEmpty(postLogoutUri))
{
if (postLogoutUri.StartsWith("/"))
{
// transform to absolute
var request = context.Request;
postLogoutUri = request.Scheme + "://" + request.Host + request.PathBase + postLogoutUri;
}
logoutUri += $"&returnTo={ Uri.EscapeDataString(postLogoutUri)}";
}
context.Response.Redirect(logoutUri);
context.HandleResponse();
return Task.CompletedTask;
},
OnRedirectToIdentityProvider = context =>
{
context.ProtocolMessage.SetParameter("audience", "MY_OWN_AUDIENCE_URL");
return Task.FromResult(0);
}
};
});
Can someone please explain why there are two audiences in my acces token?
The second audience is the userinfo endpoint. The userinfo endpoint is part of the OpenID Connect protocol; it exposes the end-user's profile information and is present because of the openid scope.
When Auth0 receives an authorization request, it checks the request's audience and scope parameters. If the audience is a custom API, and if the scope includes openid, then the access_token will include two audiences: one for your custom API, the other for the Auth0 userinfo endpoint.
Here is a supporting quote from https://auth0.com/docs/tokens/access-token
When the audience is set to a custom API and the scope parameter includes the openid value, then the generated Access Token will be a JWT valid for both retrieving the user's profile and for accessing the custom API. The aud claim of this JWT will include two values: YOUR_AUTH0_DOMAIN/userinfo and your custom API's unique identifier.
WORKING
I got it working with the next code placed in ConfigureServices in the Startup class. In the List from Configuration I placed the audience from Auth0 userinfo API and my own API.
// Multiple audiences
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateAudience = true,
ValidAudiences = Configuration.GetSection("Auth0:Audiences").Get<List<string>>(),
ValidateLifetime = true
};