My SignalR Hub requires users to be authenticated and the following line gives me user's Id:
var userId = Context.UserIdentifier;
Similarly, I can get the whole set of claims with:
var user = Context.User.Claims;
This works fine if I use SignalR locally but if I switch to Azure SignalR Service, I get a null value in Context.UserIdentifier. I also get no claims.
Here's what I'm changing in my Startup.cs:
In the ConfigureServices() method, I use
services.AddSignalR().AddAzureSignalR(Configuration["AzureSignalR:ConnectionString"]);
instead of
services.AddSignalR();
And in the Configure() method, I use:
app.UseAzureSignalR(routes =>
{
routes.MapHub<Hubs.MyHub>("/chat");
});
instead of:
app.UseSignalR(routes =>
{
routes.MapHub<Hubs.MyHub>("/chat");
});
Do I need anything else in Azure SignalR configuration to make sure I get user's claims? Any idea why this one change prevents claims from coming through?
P.S. I'm using Azure AD B2C for user authentication and as I said, if I use SignalR locally, everything works which means the code that handles grabbing JWT token from QueryString is working fine.
SignalR service will automatically inherit the claims from your authenticated user, no special configuration is needed. I just tried Azure AD B2C sample with SignalR service and the claims can be get from HubCallerContext.
Could you please check the SignalR access token returned from negotiation to see whether the claims are returned from server at the first place? (Decode it from base64 then you'll see the claims)
Related
I have an ASP.NET Core 6 MVC / Web API app I am deploying to Azure which uses the ASP.NET Authentication Framework. It uses cookie authentication with VueJs on the front end.
When I deploy to Azure Web Services, the [Authorize] attribute returns a 401 for all Patch, Put or Post calls. However, for all Get calls, the [Authorize] attribute works fine, and the API call is authenticated.
I've tried removing the [Authorize] attribute and inspected the claims and identity. Again, for all non Get calls, the identity is empty and User.Identity.IsAuthenticated is false.
But if I just change it back to a Get call, then all identity information comes through.
I can't think of any reason why the .NET authentication stack would great a Get call differently than a Post call when deployed on Azure.
Locally on my dev machine, and on a regular IIS deployment everything works fine. I've inspected the http packets, and the identity cookie is being sent by the client.
Any pointers on where to look is appreciated.
I have come across the scenario when using postman to create the users Which uses POST request.
GET https://graph.microsoft.com/v1.0/users
Even for GET , i was getting unauthorized as previously read permissions are not given and invalid bearer tpoken was given
You must be missing receiving auth access token , please add the authorization header in the code which is done In the Configure method in Startup.cs class
app.UseSession();
app.Use(async (context, next) =>
{
var JWToken = context.Session.GetString("Token");
if (!string.IsNullOrEmpty(Token))
{
context.Request.Headers.Add("Authorization", "Bearer " + Token);
}
await next();
});
app.UseAuthentication();
app.UseAuthorization();
check the scope is provided in controller part where [Authorize] attribute is given.
Check Protect a web API with the Microsoft identity platform - Microsoft Entra | Microsoft Learn
I could get the GET request response successfully after giving below permissions
I have these Directory.Read.All and User.Read delegated and application permissions only.
POST request needs write permissions , in my case to create users , it requires User.ReadWrite.All and Directory.ReadWrite.All Application permissions
Create User - Microsoft Graph v1.0 | Microsoft Learn
After giving required permissions and getting admin grant consent .
I could execute the post request successfully and create the users
Please check POST request requirements and permissions needed and make sure they are granted admin consent.It can be permissions with scopes that are granted to particular web api.
Make sure the access token or user interaction is done and permissions required are granted.
I have a React SPA which uses msal. I have configured Azure AD as Identity Provider for my AADB2C. I can signIn/signOut and other operations.
If my user signs out off my application, I want to also sign out of my Identity Provider. I looked a bit into this matter 1, 2, 3, 4, 5.
At this moment, I use msal's logoutRedirect method.
const url = new URL(AadEndSessionEndpoint);
url.searchParams.append('post_logout_redirect_uri', SPAUrl);
instance.logoutRedirect({
postLogoutRedirectUri: url.toString()
});
What happens, after my user signs out of my AADB2C, he gets redirected to the AAD end_session_endpoint. I can sign out there as well, but my user gets stuck there. Even though I'm passing the post_logout_redirect_uri query parameter to go back to my app, it ignores it.
How could I make this work?
You are doing an RP Initiated Logout in OpenID Connect terms, meaning you need to also send the id_token_hint query parameter.
I can also confirm that sending both query string parameters logs out successfully for my Azure developer account:
url.searchParams.append('post_logout_redirect_uri', SPAUrl);
url.searchParams.append('id_token_hint', myIdToken);
I think the MSAL library requires you to use getAccount instead:
const account = msalInstance.getAccount();
await msalInstance.logoutRedirect({
account,
postLogoutRedirectUri: "https://contoso.com/loggedOut"
});
UPDATE
Your code above is not right - the post logout redirect URI should be that of your own app - I expect the library already knows the end session endpoint location - so just do this:
instance.logoutRedirect({
postLogoutRedirectUri: SPAUrl
});
At the same time it is worth being aware that the full standards based GET URL should look like this. With the knowledge of the expected URL you can check that you are sending the right request via browser tools:
https://[AadEndSessionEndpoint]?id_token_hint=[myIdToken]&post_logout_redirect_uri=[SPAUrl]
The end session endpoint should be a value such as this by the way:
https://login.microsoftonline.com/7f071fbc-8bf2-4e61-bb48-dabd8e2f5b5a/oauth2/v2.0/logout
I am using Azure mobile app services with Xamarin Forms.
In my app, I use web social media authentication (Facebook, Twitter, Google) configured in the azure portal.
I am taking the sid gotten from CurrentClient.Id to match it with users in my Easy Tables. However, for some users, after logging in with the same account and same provider, no match is found in my database because the sid is different! I am 100% sure that it is the same account used to login before, yet I get a different sid. How is that possible? Shouldn't it remain the same with every login or what's the whole point of it then?
You are using Azure App Service Authentication for this. There is a stable ID that is available within the JWT that you pass to the service. You can easily get it from the /.auth/me endpoint (see https://learn.microsoft.com/en-us/azure/app-service/app-service-authentication-how-to#validate-tokens-from-providers )
When you GET /.auth/me with the X-ZUMO-AUTH header set to the authenticationToken returned from the login, the user.userId field will be populated with a stable ID. So, the next question is "how do I add this / compare this within the Node.js backend?" Fortunately, the HOW-TO FAQ for Node.js explicitly answers this. Short version is, use context.user.getIdentity() (an async method) to get the identity, then do something with it:
function queryContextFromUserId(context) {
return context.user.getIdentity().then((data) => {
context.query.where({ id: data.userId });
return context.execute();
});
}
function addUserIdToContext(context) {
return context.user.getIdentity().then((data) => {
context.itme.id = data.userId;
return context.execute();
});
}
table.read(queryContextFromUserId);
table.insert(addYserIdToContext);
table.update(queryContextFromUserId);
table.delete(queryContextFromUserId);
The real question here is "what is in the data block?" It's an object that contains "whatever the /.auth/me endpoint with the X-ZUMO-AUTH header produces", and that is provider dependent.
The mechanism to figure this out.
Debug your client application - when the login completes, inspect the client object for the CurrentUser and get the current token
Use Fiddler, Insomnia, or Postman to GET .../.auth/me with an X-ZUMO-AUTH header set to the current token
Repeat for each auth method you have to ensure you have the formats of each one.
You can now use these in your backend.
We have a SaaS web app and our clients are requiring SSO authentication for each of them. We are using AzureADB2C and it works great, but now are looking at adding SSO.
I put in the SSO setup into the B2C tenet and it works great, but really messed up our login screen with a "MyCompanySSO" button to log in with, on our customer-facing login screen.
So now my idea is to have a separate user flow that handles each SSO setup. Starting with us. We'd go to MyCompany.OurSaaSApp.us and that'd forward them directly to the user flow endpoint and prompt them to login with their SSO account (AzureAD).
This all seems to try to work, but I'm getting these errors within the AzureADB2C middleware:
Microsoft.AspNetCore.Authentication.OpenIdConnect.OpenIdConnectHandler:Warning: .AspNetCore.Correlation. state property not found.
Microsoft.AspNetCore.Authentication.OpenIdConnect.OpenIdConnectHandler:Information: Error from RemoteAuthentication: Correlation failed..
Then I get pumped out onto a error page and the login fails.
So 2 things...
1.) Am I going in the right direction knowing what we're wanting to accomplish
2.) What do we need to do to resolve this?
Thanks everyone for the help, it's been greatly appreciated.
(note:)
Just to reiterate. The SSO works properly when the custom identity provider is attached to the existing SignUpOrIn UserFlow I have configured in the app. I'm only getting this error when I try to use another UserFlow that I want to use specifically for this SSO.
I'm not sure about that specific error, although "state" parameter is a parameter that your app sends in the request that will be returned in the token for correlation purposes.
Using and different policy for each federation sounds like the right approach, but if you are doing from a single instance of your app, you'll need to modify the OIDC protocol message with the correct authority (ie policy) on redirect.
In your OIDC middleware configuration, set up a handler for the RedirectToIdentityProvider notification. Then handle it with something like:
private Task OnRedirectToIdentityProvider(RedirectToIdentityProviderNotification<OpenIdConnectMessage, OpenIdConnectAuthenticationOptions> notification)
{
//var policy = notification.OwinContext.Get<string>("Policy");
var tenantSegment = notification.Request.Path.Value.Split(new char [] { '/'}, StringSplitOptions.RemoveEmptyEntries)[0];
if (!string.IsNullOrEmpty(tenantSegment) && !tenantSegment.Equals(DefaultPolicy))
{
notification.ProtocolMessage.IssuerAddress = notification.ProtocolMessage.IssuerAddress.ToLower().Replace(DefaultPolicy.ToLower(), $"B2C_1A_{tenantSegment.ToLower()}_SignUpSignInPolicy");
}
return Task.FromResult(0);
}
If you need to inject anything else tenant-related, that would be the place to do it.
I am using the following bits against my Azure AD to authenticate with ASP.NET Core.
https://azure.microsoft.com/en-us/resources/samples/active-directory-dotnet-webapp-openidconnect-aspnetcore/
https://github.com/Azure-Samples/active-directory-dotnet-webapp-openidconnect-aspnetcore
I have the basic login/auth working after creating an Azure AD app. User can login/logout.
My question is given this, what's the best way when a user Auth's to log to a DB? I thought about making the redirect URL to an endpoint, saving, then just redirecting back to "Home" but is that ideal?
Also, is it possible to retrieve a bearer token via this approach? Or does this require another type of call or extending "scope"? So that for example I could retrieve the authenticated users Manager.
https://graph.microsoft.com/v1.0/me/manager
My question is given this, what's the best way when a user Auth's to log to a DB? I thought about making the redirect URL to an endpoint, saving, then just redirecting back to "Home" but is that ideal?
This way only able to log those who already sign-in your app successfully. It is not able to log those users who are attempt to sign-in your app but enter the wrong password.
Azure AD already provide lots of report to gain visibility into the integrity and security of your organization’s directory.( refer here)
And if you are using the Azure AD Premium, you can review the sign-in activities via the Azure new portal below:
And if you want to store the sign-in activity in your web app, you can write the custom code after the token is verified. Here is the code for your reference:
// Configure the OWIN pipeline to use OpenID Connect auth.
app.UseOpenIdConnectAuthentication(new OpenIdConnectOptions
{
ClientId = Configuration["AzureAD:ClientId"],
Authority = String.Format(Configuration["AzureAd:AadInstance"], Configuration["AzureAd:Tenant"]),
ResponseType = OpenIdConnectResponseType.IdToken,
PostLogoutRedirectUri = Configuration["AzureAd:PostLogoutRedirectUri"],
Events = new OpenIdConnectEvents
{
OnRemoteFailure = OnAuthenticationFailed,
OnTokenValidated = context => {
//write the custom code to store users login-in
return Task.FromResult(0); }
},
});
Also, is it possible to retrieve a bearer token via this approach?
Yes. We can get the token after receive the authorization code. You can refer the code sample here to acquire the token from asp.net core app.