Not getting .AspNetCore.AzureADCookie when authenticating postman against Azure Active Directory - asp.net-core

We are developing a web application communicating with its backend API. API is written in .NET Core and is running in Azure and is using OpenID authentication against Azure Active Directory. Configuration of the authentication process is below (as you can see we're using cookie based authentication):
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = AzureADDefaults.CookieScheme;
options.DefaultChallengeScheme = AzureADDefaults.AuthenticationScheme;
options.DefaultSignInScheme = AzureADDefaults.CookieScheme;
})
.AddAzureAD(options =>
{
configuration.Bind("AzureAd", options);
});
services.Configure<CookieAuthenticationOptions>(AzureADDefaults.CookieScheme, options =>
{
options.Cookie.HttpOnly = true;
options.Cookie.SecurePolicy = CookieSecurePolicy.Always;
options.Cookie.SameSite = SameSiteMode.Lax;
options.Cookie.MaxAge = new TimeSpan(7, 0, 0, 0);
});
services.Configure<OpenIdConnectOptions>(AzureADDefaults.OpenIdScheme, options =>
{
options.Authority = options.Authority + "/v2.0/";
options.TokenValidationParameters.ValidateIssuer = false;
});
We want to test our application API in Postman and we have set up a request with authentication against AAD (configuration below). Postman is able to make it through authentication and we get the access_token, however the request to API fails.
When we compared Postman cookies and browser cookies we discovered, that browser contains a cookie postman is missing .AspNetCore.AzureADCookie. It's Friday afternoon and we really got into desperation phase and have no clue what may be wrong. How can we make Postman to call AAD in a way it returns such cookie in response and adds it to the API request.

You should be able to use your browser cookies by installing Postman Interceptor extension.
Please try the same and let me know if it works.
https://learning.postman.com/docs/sending-requests/capturing-request-data/interceptor/#syncing-cookies
You can also ref the following ->
Postman is not using cookie

Related

Teams App oauth authentication Issue on Firefox in Iframe

I am facing issue on Firefox for Teams APP authentication. I have a Configurable Tab which is a Blazor web application. In the Tab, you sign in using an Oauth provider which is not Azure Ad. On browser login works as expected but when open in Teams using Teams app, It never passes the authentication cookies from login pop up to calling page. To make it work on firefox , I have to disable Enahnced tracking protection. I understand that Firefox disabled Iframe to Iframe cookies passing, but does anyone know if there is a way I can handle it in better way without diabling this feature.
This works on Edge and Chrome without disabling any feature. Here is the code from startup.cs file:
services.AddAuthentication(options =>
{
options.DefaultScheme = CookieScheme;
options.DefaultChallengeScheme = OAuthScheme;
options.DefaultAuthenticateScheme = CookieScheme;
options.DefaultSignInScheme = CookieScheme;
})
.AddCookie(CookieScheme, options =>
{
options.Cookie.SecurePolicy = CookieSecurePolicy.Always;
options.Cookie.SameSite = SameSiteMode.None;
options.ExpireTimeSpan = TimeSpan.FromMinutes(9.5);
options.SlidingExpiration = false;
options.Events = new CookieAuthenticationEvents
{
OnValidatePrincipal = RefreshTokenIfRequired
};
})
.AddOAuth(OAuthScheme, options =>
{
var Settings = JsonConvert.DeserializeObject<ApiSettings>(Configuration["oauth"]);
options.ClientId = Settings.ClientId;
options.ClientSecret = Settings.ClientSecret;
options.AuthorizationEndpoint = Settings.AuthEndpoint;
options.TokenEndpoint = Settings.TokenEndpoint;
options.CallbackPath = new PathString("/oauth/callback");
options.SaveTokens = true;
});
It looks like you're trying to implement the signing process yourself, and especially in the desktop client is where you'll run into exactly the problems you're facing. Instead of implementing signing/cookies/etc., you should implement the actual SSO capabilities that Teams has specifically built to support you. Please see here for more: https://learn.microsoft.com/en-us/microsoftteams/platform/tabs/how-to/authentication/tab-sso-overview
If you're leveraging Azure Active Directory, that's the easiest, but this SSO capability even supports alternative oAuth providers - see https://learn.microsoft.com/en-us/microsoftteams/platform/tabs/how-to/authentication/auth-flow-tab

How to combine multiple authentication schemes for different types of clients (user/pass and client/secret) in a Blazor WASM project?

I have a Blazor WASM project with a Blazor Client and ASP.NET core server. I can authenticate with user/password using the following code:
services
.AddDefaultIdentity<ApplicationUser>(
options => options.SignIn.RequireConfirmedAccount = true)
.AddRoles<IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>();
services
.AddIdentityServer()
.AddApiAuthorization<ApplicationUser, ApplicationDbContext>();
services
.AddAuthentication()
.AddIdentityServerJwt();
services.AddTransient<IProfileService, ProfileService>();
services.AddAuthorization(options =>
{
options.AddPolicy("ApiScope", policy =>
{
policy.RequireAuthenticatedUser();
policy.RequireClaim("scope", "api1");
});
});
When I add the following code, I can successfully authenticate with clientcredentials from a console client. But then the Blazor client user/password authentication stops working.
...
services
.AddIdentityServer()
.AddApiAuthorization<ApplicationUser, ApplicationDbContext>()
+.AddInMemoryApiScopes(Config.ApiScopes)
+.AddClientStore<ClientStore>()
+.AddDeveloperSigningCredential();
services
.AddAuthentication()
.AddIdentityServerJwt();
+services
+ .AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
+ .AddJwtBearer(JwtBearerDefaults.AuthenticationScheme, options =>
+ {
+ options.Authority = "https://localhost:44311";
+ options.TokenValidationParameters = new TokenValidationParameters
+ {
+ ValidateAudience = false,
+ };
+ });
...
In the browser while trying to authenticate in the Blazor client, the console prints:
info: Microsoft.AspNetCore.Authorization.DefaultAuthorizationService[2]
Authorization failed. These requirements were not met:
DenyAnonymousAuthorizationRequirement: Requires an authenticated user.
I have tried a lot, but I'm not able to make both work together. It seems that somehow this configuration requires authentication for everything, even the pages/controllers that are marked AllowAnonymous. So, when I try to authenticate, it gives me an error telling me the user must be authenticated: DenyAnonymousAuthorizationRequirement. The policy, "ApiScope" is only intended for the clientcredentials client, not for the Blazor client. If removed, the RequireAuthenticatedUser call doesn't make a difference, same error.
Any help is appreciated.

Identity Server 4 token expiration Api vs ClientApp

i'm currently building a WebApp with authentication/authorization to access it and also to access several WebAPI's, all pointing to a Identity Server 4 host.
I have followed the official documentation of IdentityServer4 and its demos and for client authentications, token generations, user logging in, API's being called succesfully with tokens, all work fine, apparently, but recently i noticed that after some time of inactivity, the call to the API's start to receive 401 but the client application is still up with the same token.
It's like this:
Launch browser with debugging
Login with some user
Go to a view that calls one API to retrieve data for it
Keep navigating and testing, and everything else works fine
Now, the problem (after the previous step 4)
Stop debugging but keeping the browser up and running (keeping the cookies)
Changing code, implementing new stuff (basically passing some time)
Launch debug again
Using the same sessions/cookie on the already open browser, trying to navigate on the application works fine and does not required new login
Navigating to a view that will call the API using the current token, gives me the 401 when previously didnt
What i found out is that the token is expired, Visual Studio output points that out (also checking the token on https://jwt.io/ i can confirm the datetime).
Why the same token works fine for the ClientApp while invoking the API doesn't? Do i require to manually generate a new token because of the API's calls?
The configurations i'm using are:
---CLIENT application---
new Client
{
ClientId = "idWebApp",
ClientSecrets = new List<Secret> { new Secret("secret".Sha256()) },
AllowedGrantTypes = GrantTypes.Hybrid,
AllowAccessTokensViaBrowser = false,
EnableLocalLogin = true,
RedirectUris = { "http://localhost:5901/signin-oidc" },
FrontChannelLogoutUri = "http://localhost:5901/signout-oidc",
PostLogoutRedirectUris = { "http://localhost:5901/signout-callback-oidc" },
AllowOfflineAccess = true,
AllowedScopes = new List<string>
{
IdentityServerConstants.StandardScopes.OpenId,
IdentityServerConstants.StandardScopes.Profile,
IdentityServerConstants.StandardScopes.OfflineAccess,
"apiAccess",
},
RequireConsent = false,
}
---API resource---
(Just using simple ctor to initialize with a 'Name')
new ApiResource("apiAccess")
---Custom Claims---
new IdentityResource()
{
Name = "appCustomClaims",
UserClaims = new List<string>()
{
"customRole"
}
}
---Startup code of ClientApp---
services.AddAuthentication(options =>
{
options.DefaultScheme = "Cookies";
options.DefaultChallengeScheme = "oidc";
})
.AddCookie("Cookies")
.AddOpenIdConnect("oidc", options =>
{
options.Authority = "http://localhost:5900";
options.RequireHttpsMetadata = false;
options.ClientId = "idWebApp";
options.ClientSecret = "secret";
options.ResponseType = "code id_token";
options.Scope.Add("profile");
options.Scope.Add("offline_access");
options.ClaimActions.MapUniqueJsonKey("offline_access", "offline_access");
options.Scope.Add("appCustomClaims");
options.ClaimActions.MapJsonKey("customRole", "customRole");
options.Scope.Add("apiAccess");
options.GetClaimsFromUserInfoEndpoint = true;
options.SaveTokens = true;
options.TokenValidationParameters.RoleClaimType = "customRole";
});
Why the same token works fine for the ClientApp while invoking the API
doesn't?
Two things:
The expiration time of the access token is unrelated to your actions.
Once issued a JWT token can't be changed. By default the token expires after 3600 seconds.
The difference between the application and the api: the application uses cookies, the api a bearer token.
The cookie has its own expiration logic. This means that it expires at a different time, unrelated to the expiration time of the access token, and also can be kept alive because the cookie can be updated, unlike the JWT access token.
For offline_access you require to obtain a new access token, using the refresh token. As explained here.

How to implement multi-tenant JWT Authentication with different AWS Cognito UserPools per tenant with .Net Core

I have a diifferent AWS Cognito UserPool per Tenant, but I need to be able to validate the token depending on the tenant-specific request.
I'm aware that there is currently no support for this in .Net Core. Can anyone advise a way to handle this? Can you dynamically set the JWT Bearer once the application is running?
To get it working, I've tried to add multiple JWTBearers in the Startup.cs, but I encounter the error: InvalidOperationException: Scheme already exists: Bearer.
services.AddAuthentication(o =>
{
o.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
o.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(cfg =>
{
cfg.SaveToken = true;
cfg.TokenValidationParameters = <TENANT_1_CONFIG>.TokenValidationParameters();
})
.AddJwtBearer(cfg =>
{
cfg.SaveToken = true;
cfg.TokenValidationParameters = <TENANT_2_CONFIG>.TokenValidationParameters();
});
Ideally I'd like to be able to set this config once the application is running, depending on the request.

JWT Authentication

My team is building a web api in .net core. We use token authentication to authenticate any client, the token comes form the Azure AD.
We put this code in Startup.cs
app.UseJwtBearerAuthentication(options => {
options.AutomaticAuthenticate = true;
options.AutomaticChallenge = true;
options.Authority = "https://login.windows.net/1da3434a9-e5a6-4e9e-80c3-aca8ed37cb03";
options.Audience = "https://test.onmicrosoft.com/test_api";
options.RequireHttpsMetadata = false;
});
services.AddCors(options =>
{
// Define one or more CORS policies
options.AddPolicy("AllowAll",
builder =>
{
builder.AllowAnyOrigin()
.AllowAnyHeader()
.AllowAnyMethod()
.AllowCredentials();
});
});
This one only work when we allow anonymous access. I checked the token, and the token is valid. But every time we hit controller it will throw cors error. even though we enable cors
The sequence of adding middleware does matter!
To enable CORS for your entire application add the CORS middleware to
your request pipeline using the UseCors extension method. Note that
the CORS middleware must proceed any defined endpoints in your app
that you want to support cross-origin requests (ex. before any call to
UseMvc).
You should put services.AddCors above almost everything that might redirect your users via 401.
You cannot combine AllowCredentials & AllowAnyOrigin. Pick a specific origin and your request will likely work.