How to use GamilService with OIDC Authentication in a Blazor Webassembly .net6 client - gmail-api

I would like to use GmailService (Google.Apis.Gmail.v1) in my Blazor-Wasm app.
I have already implemented the OIDC-Authentication with
builder.Services.AddOidcAuthentication(options =>
{
builder.Configuration.Bind("Google", options.ProviderOptions);
});
and CascadingAuthenticationState and AuthorizeRouteView.
The authentication is successful, I will be requested to allow permissions to my gmail account.
now I want to create and use a GmailService insance in my razor page, but I cannot find an example, how do it.
can you please help me?

Related

How to use Azure AppRoles in Blazor Server with Azure Active Directory

I have an up and running .NET 5 Web-API with a Blazor Server Client in Production. I'd like to switch from Individual User Accounts to Azure AD using App Roles to authenticate specific Users in my Controllers. I found lots of Information regarding Webassembly but none for Blazor Server.
Has somebody a working Solution for a .NET 5/6 Web-Api with a Blazor Server Client and integrating Azure App Roles?
Apps are already registered in the Azure Portal and so forth, I just need to know how to pass the App Roles specific stuff to my API, so my Controller can work with the [Authorize("Admin")] stuff. I suspect it will use Bearer Tokens aswell.
Edit:
Thanks a lot for reading. So I figured out that if I use something like this in my Controller only using the [Authorize] Attribute without any roles:
var identities = HttpContext.User.Identities.ToList();
foreach (var item in identities)
{
if (item.RoleClaimType == "admin")
{
// return or do something
}
}
It would just work fine but there has to be some smoother solution for this or am I doing this completly wrong? When I look at the WASM Samples, they pick up the AppRoles with their token and the Controller simply can use the [Authorize(Roles = "xyz")] Attribute. What am I missing here? :/
Btw, this is how my Program.cs looks right now:
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApi(options =>
{
builder.Configuration.Bind("AzureAd", options);
options.TokenValidationParameters.RoleClaimType =
"admin";
options.TokenValidationParameters.RoleClaimType = "doku";
},
options => { builder.Configuration.Bind("AzureAd", options); });
Thank you guys/gals <3
Please check if the given references are of use in your case.
A SERVER API app can authorize users to access secure API endpoints with authorization policies for security groups, AAD Administrator Roles, and App Roles
In Program.cs of a SERVER app, specify the claim as roleclaim
example:
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApi(options =>
{
Configuration.Bind("AzureAd", options);
options.TokenValidationParameters.RoleClaimType =
"http://schemas.microsoft.com/ws/2008/06/identity/claims/role";
},
options => { Configuration.Bind("AzureAd", options); });
Then you can use admin role on authorization controller to access
[Authorize(Roles = "admin")]
Here in App roles section you can see the configuration for both
server and client.
Edit the app role in the manifest editor in portal and then give
proper api permissions , expose scopes and grant permission for admin
consent >see Add app roles and get them from a token .And the
procedural logic must contain those scopes required by api.
Note : The appRoles manifest property of both the client and the
server Azure portal app registrations must include the same configured
roles.
Please check this for more detailed information which guides for both server and client apps.
Other references:
using-app-roles-with-AAD-blazor-server-client scenario | codemaze.com
quickstart-configure-app-expose-web-apis
quickstart-configure-app-access-web-apis

using MSAL Authentication in WASM Application calls to Microsoft Graph and custom API

I implement this to login the user using WASM standalone app.
builder.Services.AddMsalAuthentication(options =>
{
builder.Configuration.Bind("AzureAd", options.ProviderOptions.Authentication);}
It works great. When I try to add the scope for the graph and my api. It does not allow the login.
builder.Services.AddMsalAuthentication(options =>
{
builder.Configuration.Bind("AzureAd", options.ProviderOptions.Authentication);
options.ProviderOptions.DefaultAccessTokenScopes.Add("https://graph.microsoft.com/User.Read");
options.ProviderOptions.DefaultAccessTokenScopes.Add("https://xsc.com/xxEmployees.Read.All");
)
The error says AADSTS28000: Provided value for the input parameter scope is not valid because it contains more than one resource. How do I get this to work?
I looked at AcquireTokenSilent it uses a Microsoft.Identity.Client is this my only option. If it is my next question is how to I take my authenticated user AuthenticationStateprovider and create a IAccount for the AcquireTokenSilent method. Any ideas or other ways to try this would be greatly appreciated.
Msal is based on azure ad so that along the policy of azure ad, you can't generate an access token for two or more types of scopes at the same time.
This page also mentioned it, the only way seems to generate token seperately and call api for 2 times.

Blazor WASM calling Azure AAD secured Functions API

I have an Azure Functions API which uses Azure Active Directory authentication. I can test locally and deployed using a browser and curl calls in a process of:
Get a code
Use the code to get a token
Pass the token to authenticate and get the function result.
I now want to call this API from my Blazor WASM app but I'm sure there must be a nice MSAL call to do all the authentication but I cannot find any documentation on what that might be.
Does anyone have a code snippet to illustrate what needs to happen?
Further Information
My Azure Functions App and Blazor WASM client are not part of the same project and are hosted on different sub-domains of Azure hypotheticalapi.azurewebsites.net and hypotheticalweb.azurewebsites.net.
The web client application registration has API Permissions for the API and the API has an application registration which exposes itself with the scope that the client app has permissions for.
Again, the API and Web app work individually. I just don't seem able to get them to talk.
I have been following the "ASP.NET Core Blazor WebAssembly additional security scenarios" documentation but after several attempts I keep coming back to the error:
Microsoft.JSInterop.JSException: invalid_grant: AADSTS65001:
The user or administrator has not consented to use the application with ID 'e40aabb0-8ed5-4833-b50d-ec7ca4e07996' named 'BallerinaBlazor5Wasm'.
Send an interactive authorization request for this user and resource.
Even though I have revoked/deleted the client's permissions on the API, it has never repeated asking for consent. Is there a way I should clear the consent I previously gave? No idea how I might do that.
This GitHub Issue appears to be relevant.
I was stuck for the last two weeks with the same error code in the same setting: Blazor WASM talking to an AAD secured Azure Functions app.
What appeared to be a problem in my case was the scopes that I was listing in the http request when contacting AAD identification provider endpoints. Almost all examples I came across use Microsoft Graph API. There, User.Read is the scope that is given as an example. My first though was that even when I am contacting my own API I have to include the User.Read scope in the request because I was reasoning that this scope is necessary to identify the user. However, this is not the case and the only scope that you have to list when you call the authorize and token endpoints is the one that you exposed under the "Expose an API blade" in your AAD app registration.
I am using the OAuth2 authorization code in my example and not the implicit grant. Make sure that in the manifest of your API registration you have set "accessTokenAcceptedVersion": 2 and not "accessTokenAcceptedVersion": null. The latter implies the use of implicit flow as far as I know.
The scope the I exposed in my API is Api.Read. You can expose more scopes if you need but the point is that you only ask for scopes that you exposed.
I also have both following options unticked (i.e. no implicit flow). However, I tried with selecting "ID token" and it still worked. Note that the "ID token" option is selected by default if you let the Azure Portal create your AAD app registration from your function app Authentication blade.
Blazor code
Program.cs
This code has to be added.
builder.Services.AddScoped<GraphAPIAuthorizationMessageHandler>();
builder.Services.AddHttpClient("{NAME}",
client => client.BaseAddress = new Uri("https://your-azure-functions-url.net"))
.AddHttpMessageHandler<GraphAPIAuthorizationMessageHandler>();
builder.Services.AddScoped(sp => sp.GetRequiredService<IHttpClientFactory>()
.CreateClient("{NAME}"));
builder.Services.AddMsalAuthentication(options =>
{
builder.Configuration.Bind("AzureAd", options.ProviderOptions.Authentication);
// NOTE: no "api://" when providing the scope
options.ProviderOptions.DefaultAccessTokenScopes.Add("{you API application id}/{api exposed scope}");
});
appsetting.json
"AzureAd": {
"Authority": "https://login.microsoftonline.com/{aad tenant id}",
"ClientId": "{application id of your blazor wasm app}",
"ValidateAuthority": true
}
GraphAPIAuthorizationMessageHandler.cs
Note that this class can have a different name. you'll then also reference a different name in Program.cs.
public class GraphAPIAuthorizationMessageHandler : AuthorizationMessageHandler
{
public GraphAPIAuthorizationMessageHandler(IAccessTokenProvider provider,
NavigationManager navigationManager)
: base(provider, navigationManager)
{
ConfigureHandler(
authorizedUrls: new[] { "https://your-azure-functions-url.net" },
// NOTE: here with "api://"
scopes: new[] { "api://{you API application id}/{api exposed scope}" });
}
}
I hope this works. If not, let me know.
At least you need to get the access token, then use the token to call the function api. In this case, if you want to get the token in only one step, you could use the client credential flow, MSAL sample here, follow every part on the left to complete the prerequisites.
The following are the approximate steps(for more details, you still need to follow the sample above):
1.Create a new App registration and add a client secret.
2.Instantiate the confidential client application with a client secret
app = ConfidentialClientApplicationBuilder.Create(config.ClientId)
.WithClientSecret(config.ClientSecret)
.WithAuthority(new Uri(config.Authority))
.Build();
3.Get the token
string[] scopes = new string[] { "<AppId URI of your function related AD App>/.default" };
result = await app.AcquireTokenForClient(scopes)
.ExecuteAsync();
4.Call the function API
httpClient = new HttpClient();
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", result.AccessToken);
// Call the web API.
HttpResponseMessage response = await _httpClient.GetAsync(apiUri);
...
}

How to Authenticate WPF Application with AAD B2C to gain access to Azure App Service

I'm quite stuck at the moment trying to implement authentication into a project I'm working on. The end goal of this project is to have two WPF apps and on web based app hosted on Azure. One WPF app is for an administrator, the other for staff, and lastly the web app for customers. Each application will be connected to one Azure App Service for a shared database and needs to have authentication so separate all the users. For authentication I am planning on using Azure Active Directory B2C.
I've been researching and trying to implement this for several days now on one of the WPF apps but as I stated before I'm quite stuck. From what I understand, the only way to do B2C authentication for WPF is through client managed authentication. Following the code shown on the Azure tutorial sites, other SO posts, and the Azure Git Repos, I have come up with the following code:
System.Net.ServicePointManager.SecurityProtocol = System.Net.SecurityProtocolType.Tls12;
authResult = await App.PublicClientApp.AcquireTokenAsync(App.ApiScopes,
GetUserByPolicy(accounts, App.PolicySignUpSignIn), UIBehavior.SelectAccount,
string.Empty, null, App.Authority);
Newtonsoft.Json.Linq.JObject payload = new Newtonsoft.Json.Linq.JObject();
payload["access_token"] = authResult.AccessToken;
MobileServiceClient msclient = new MobileServiceClient(App.AzureAppService);
MobileServiceUser user = await msclient.LoginAsync(
MobileServiceAuthenticationProvider.WindowsAzureActiveDirectory, payload);
Everything starts off great and I'm able to get my Sign-In policy to display. After logging in, I am given an IdToken and an AccessToken. After creating a JObject and adding the access token to it, I attempt to use it to login with my MobileServiceClient. But that's where I am having issues. No matter what I do, no matter what I try, I only get an exception with a 401 Error telling me I'm unauthorized. And this is the point I've been stuck at for the past few days.
Obviously I'm not doing anything special here and I imagine many people have done this before me but I just can't seem to get past this point and was hoping someone may be able to offer me some guidance. Am I way off track? Is there a better way that I could be doing this? Any suggestions or advice would be greatly appreciated as I am very new to Azure.
Thanks all!
Update:
Here's how I have my Azure Settings:
On the app service side
Client Id: "{Client Id of the AAD B2C App}"
Issuer URL: "login.microsoft.com{TennatName}.onmicrosoft.com/v2.0/.well-known/openid-configuration"
Allowed Token Audiences: "https://{App Service Name}.azurewebsites.net" (App Service URL)
On B2C side:
Web and native client enabled
Web Reply URL: "https://{AppServiceName}.azurewebsites.net/.auth/login/add/callback"
Native App: I did not know what custom redirect URL to have so I have both
"{TennatName}.onmicrosoft.com://auth/" and
"{AppServiceName}.azurewebsites.net/.auth/login/add/callback"
Update 2:
My authority is login.microsoftonline.com/tfp{tenant}/{policy}/oauth2/v2.0/authorize
And my ApiScopes = { "https://{Tenant}/thisisatest/user_impersonation" };
If the authority for the client is set to https://{your-tenant-name}.b2clogin.com/tfp/{your-tenant-name}.onmicrosoft.com/{your-policy-name}/, then the issuer URL in the app service must refer to the metadata for this authority; i.e. https://{your-tenant-name}.b2clogin.com/tfp/{your-tenant-name}.onmicrosoft.com/{your-policy-name}/v2.0/.well-known/openid-configuration.

Satellizer: login using FB's access_token

I'm implementing a hybrid iOS web and native app. I'm using iOS native FB login capabilities, and sending the access_token from the native app to the web, which uses Satellizer.
The question is: can I avoid the FB permissions dialog and directly use the access_token to sign up the user and recover the JWT from the server, using the normal Satellizer flow?
Permission dialog is a must for every third party social login.
The user need to approve and to know what application he is going to use with that social network and what permissions he will give to that specific application.
I solved it doing Satellizer job of sending the access_token and storing it manually:
$http.post('/auth/facebook', {
token: receivediOSToken
}).then(function (response) {
$auth.setToken(response.data.token);
loginSuccess();
}, function () {
loginError();
});

Resources