Google Api authorize an App running in the console - c#

I want to manually authorize an app that runs in the console where there is no browser available.
Basically I need the same code as they are using on this website but the C# Equivalent.
I just can't seem to find the part in the C# Library that allows me to print a link to the console instead of opening a browser.
My current implementation I have just opens the browser and throws an Error if it cant.
GoogleClientSecrets? fromStream = await GoogleClientSecrets.FromStreamAsync( stream , taskCancellationToken );
UserCredential credential = await GoogleWebAuthorizationBroker.AuthorizeAsync( fromStream.Secrets
, scopes
, user
, taskCancellationToken
, new FileDataStore( nameof(Authorize) ) );

The GoogleWebAuthorizationBroker.AuthorizeAsync method is designed for installed applications. Installed applications will open the browser on the machine the code is running on.
The following example is designed for web applications. The application would need to be running on a web server.
public void ConfigureServices(IServiceCollection services)
{
...
// This configures Google.Apis.Auth.AspNetCore3 for use in this app.
services
.AddAuthentication(o =>
{
// This forces challenge results to be handled by Google OpenID Handler, so there's no
// need to add an AccountController that emits challenges for Login.
o.DefaultChallengeScheme = GoogleOpenIdConnectDefaults.AuthenticationScheme;
// This forces forbid results to be handled by Google OpenID Handler, which checks if
// extra scopes are required and does automatic incremental auth.
o.DefaultForbidScheme = GoogleOpenIdConnectDefaults.AuthenticationScheme;
// Default scheme that will handle everything else.
// Once a user is authenticated, the OAuth2 token info is stored in cookies.
o.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
})
.AddCookie()
.AddGoogleOpenIdConnect(options =>
{
options.ClientId = {YOUR_CLIENT_ID};
options.ClientSecret = {YOUR_CLIENT_SECRET};
});
}
These are your two options unless you are able to use service account authorization. Service account authorization is intended for server to server communication between your application and an account you the developer control. It does not work with all google apis.
options
Consider running your code once locally, then copy credentials file that is created by FileDataStore onto the server along with your code. Google .net – FileDatastore demystified
print link
There used to be a method to print the authorization link but i will have to dig around in the library for it tomorrow.

Related

How to control access on static files through .Net core 5.0 API

I have one API and one Client app (Blazor web assembly) separately.
The client app authenticates users through the Azure active directory. In the client when I have saved any file through API, I am using static files configured on Startup.cs such as :
app.UseStaticFiles(new StaticFileOptions()
{
FileProvider = new PhysicalFileProvider(Path.Combine(#"c:\", #"Resources")),
RequestPath = new PathString("/secureFile"),
});
The problem is the client application is working fine. But if someone inspects the Html and gets the image source they can directly access the files through the browser like https://localhost:44397/secureFile/profile.jpg
On the other hand, because I am using Azure active directory login, the API does not save any user information. That's why I can't use the scenario like:
app.UseAuthentication();
app.UseAuthorization();
app.UseStaticFiles(new StaticFileOptions()
{
FileProvider = new PhysicalFileProvider(Path.Combine(#"c:\", #"Resources")),
RequestPath = new PathString("/secureFile"),
OnPrepareResponse = ctx =>
{
if (!ctx.Context.User.Identity.IsAuthenticated)
{
// respond HTTP 401 Unauthorized.
ctx.Context.Response.StatusCode = (int) HttpStatusCode.Unauthorized;
ctx.Context.Response.ContentLength = 0;
ctx.Context.Response.Body = Stream.Null;
// ctx.Context.Response.Redirect("/")
}
}
});
Here the !ctx.Context.User.Identity.IsAuthenticated is always false even the client application is calling.
May Client application is Authenticating though :
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.Audience = Configuration["AAD:ResourceId"];
options.Authority = $"{Configuration["AAD:InstanceId"]}{Configuration["AAD:TenantId"]}";
});
My goal is to give access to the https://localhost:44397/secureFile/profile.jpg if the client application is calling the image source. But should block if anyone calls through the URL directly.
Any lead will help me a lot.
I have already followed article but no use in my scenario because I am using AAD login.
You mention that "the API does not save any user information," but regardless of the authentication flow, some authentication information has to be established even transiently for the individual request so that authorization can be evaluated.
In the example code you have listed, you're invoking a check on the HttpContext User claims principal to see if the user is authenticated, and you mention it's always coming back as false, even if it's coming from your client application. What's notable here is that something has to invoke the authentication flow in an application before authorization can be performed. Because nothing in the StaticFileMiddleware inherently does this, it probably never is happening during that request.
You can invoke that authentication flow yourself through the use of the ChallengeAsync() method, which is intended to "challenge the current request using the default challenge scheme. An authentication challenge can be issued when an unauthenticated user requests an endpoint that requires authentication":
https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.authentication.authenticationhttpcontextextensions.challengeasync?view=aspnetcore-6.0
You may need to customize the behavior for your particular case, especially if you have to accommodate multiple schemes, but a general starting point would be adding a using Microsoft.AspNetCore.Authentication; to ensure the HttpContext extensions are available, then adding a corresponding call to await ctx.Context.ChallengeAsync() within your flow if the user is not authenticated.
Once that runs, you can check again whether the user is both authenticated and whether they meet the authorization requirements you would like to have for your secure static files.

Where can I find a code sample for OpenId Connect sign out for c#?

Security is one of those things that once you set it up, you kinda forget about it, until something doesn't work. I have a .Net Core application that uses OpenId Connect with Azure. The sign in works fine, but we noticed a few days ago that the signout wasn't working. You could sign out of the application, but then login again directly without entering credentials. So, I have been looking around and found out that it's not good enough to clear the cookies and session, you need to go to the "end_session_endpoint" to actually clear the credentials. I have looked in a number of places, but I can't find a simple code example of how to to this. And the code examples I have tried don't seem to work. When I run locally, I can logout and it says it logged me out, but when I start the application again, I am logged in automatically right away. I understand the concept, I just don't know how to do it. Below is what my authentication looks like in the Startup.cs file:
services.AddAuthentication(options =>
{
})
.AddCookie()
.AddOpenIdConnect(options =>
{
options.Authority = Configuration["Authentication:Microsoft:OAuth"];
options.RequireHttpsMetadata = true;
options.ResponseType = OpenIdConnectResponseType.CodeIdToken;
options.UsePkce = false;
options.Scope.Clear();
options.Scope.Add("openid");
options.Scope.Add("email");
options.SaveTokens = true;
options.CallbackPath = new PathString(Configuration["Authentication:Microsoft:Callback"]);
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = false,
};
// MetadataAddress represents the Active Directory instance used to authenticate users.
options.MetadataAddress = Configuration["Authentication:Microsoft:Meta"];
options.ClientId = Configuration["Authentication:Microsoft:ApplicationId"];
options.ClientSecret = Configuration["Authentication:Microsoft:Password"];
});
Does anyone have a straight forward code example for this?
RP INITIATED LOGOUT
This is mostly a case of sending the standard message with these parameters.If I remember rightly, Azure may require the third of these to log you out successfully.
client_id
post_logout_redirect_uri
id_token_hint
EXAMPLES
Here is a C# example that sends this type of request. It uses the older .Net framework, but should be easy to follow.
In .Net Core, you can set a SignedOutCallbackPath in the OIDC properties, which must match a post_logout_redirect_uri registered against the client in Azure AD. You can then call this code in the controller and it should send the standard mesaage.
await HttpContext.SignoutAsync():
Personally I find this .NET syntax and C# layer a little unintuitive, but ultimately it is just a wrapper around the standard messages.
My Azure SPA example does an RP initiated logout, and I can confirm that the above parameters work fine with Azure AD.
ADVANCED OPTIONS
Sometimes logout can be a very tricky area to get the best usability behaviour, depending on the provider. In case useful later, another option is to use the max-age parameter from OpenID Connect during sign in. You then get an auth_time claim in the ID token. On the next redirect after auth_time has expired you can use this data to send a prompt=login parameter if required, to force the user to re-authenticate. The .NET way to do this is described in this post.
UPDATE
Here is what my SPA config looks like, with the post logout redirect URI, to check against your own configuration. RP (relying party) is your C# web app, OP (openid connect provider) is Azure AD (I never liked this type of terminology). The logout mechanics are just focused on removing the SSO cookie that Azure AD sets. Azure AD logout behaviour may not be easy to control fully though, since logout in OAuth technologies can sometimes get complex and involve multiple apps.
TEST OPTION
One option you could try is logging in and out using OAuth Tools, which is useful for troubleshooting this type of problem without needing to write code. Once you get the correct behaviour here, you'll be clearer about what you need to code:
First find your OpenID Connect metadata URL - this is my URL
Next select Add Environment, give it a name like my and enter the metadata URL - then make sure this environment is selected
Add https://oauth.tools/callback/code to Azure AD as a redirect URI
Then select Code Flow in OAuth tools, enter your development Azure AD client ID and client secret, then select Run, to trigger a redirect
Then scroll down and click Redeem Authorization Code, which will get tokens, including an ID token which might be needed for logout
Then run a Logout Flow, for which you'll need to set https://oauth.tools in Azure AD as the front channel logout URL
If you can't get logout to work as you'd like, try the prompt=login option, which will force a new login
Q & A
So OIDC logout is working but a second factor time to live is not. This is outside the OIDC specs and probably cannot be influenced by code. Try it in a new Incognito browser window and see if you have to enter the second factor. If so then it will be a cookie that you may be able to identify if you trace the HTTP traffic. Look for a configuration setting somewhere that controls this - something similar to the Curity TTL setting in this article. If there is no such setting then it may be outside your control.
Leftover browser sessions. In some ways if users let other people use their desktop sessions then all bets are off. You can get too hung up on this. Just aim to be as good as other apps. Eg are you as secure as Office 365 itself, Gmail etc?
By default (without a post logout redirect URI) the user is dumped back in the Azure login screen, which is typically not what the user wants. Instead a post logout landing screen gives your app control over the UX. A common option is to just display something like You are signed out, click here to log back in. In a C# website this would just return a view to the browser.

Can I request IdentityServer4 tokens from client if server was rebooted?

Its very difficult to ask questions on ID4. Also all relevant discussions I could google point to non-existing links for code samples.
What I have: an angular client uses ID4 auth made up of MVC pages provided by Microsoft, hosted in ASP.NET Core.
Startup.cs
services.AddDefaultIdentity<ApplicationUser>(options => options.SignIn.RequireConfirmedAccount = true)
.AddEntityFrameworkStores<AppDbContext>();
services.AddIdentityServer()
.AddApiAuthorization<ApplicationUser, AppDbContext>();
services.AddAuthentication()
.AddIdentityServerJwt();
. . .
app.UseAuthentication();
app.UseIdentityServer();
app.UseAuthorization();
authorize.service.ts
const settings: any = await response.json();
settings.automaticSilentRenew = true;
settings.includeIdTokenInSilentRenew = true;
this.userManager = new UserManager(settings);
Use case: a user logs in on the webpage, ticks Remeber Me checkbox and uses the auth'ed website parts. If the server restarts - the tokens lost and user interaction with the website becomes broken - e.g. there are no errors in the webbrowser console and nothing happens if user tries to access any server-side data. It looks like nothing is there. Not as if there is issue with the auth.
It can only be fixed by manually logout/login. Or by opening new tab and going to the app again.
Is there simple explanation on to how can I a) detect that client token is broken and b) request new token?
EDIT if a user continues to use website next working day or opens new browser tab (without server restart) the ID4 works as expected - no login required.
The fiddler:
The short answer is: nothing should break if the server process (either application backend or identityserver4-based IDP) restarts so chances are you're missing some persistence (for persisted grants) and/or shared config (e.g. token signing keys and ASP.Net data protection keys) and things are being regenerated on startup and in-memory data is being lost.
This article covers the things you need to consider to deploy a viable production service: https://docs.identityserver.io/en/latest/topics/deployment.html
With that all in place though tokens will still expire and there are a couple of ways to refresh them depending on the context and grant type in use.
To detect if a token is not valid anymore:
Use it and detect if you get a 401 response from the endpoint you're calling
Check the exp claim inside the token yourself
Use the expires_in value returned with the token and calculate the expiry time based on that
To renew it (and some libs will automate this):
Use the iframe-based silent renewal mechanism (authorize endpoint with prompt=none) - note that third part cookie restrictions come into play for this
Use a refresh token via the token endpoint (not recommended for client side apps due to the need to persist a refresh token in the client side)

using Google GmailAPI send mail not working

I need help. Program WebApplication Code C# Asp.Net
First ,I've implemented a way to put a URI in Google OAuth 2 authorization.
Download the Json file for the program to read the file and generate the token.
Error
Failed to launch browser with "https://accounts.google.com/o/oauth2/v2/auth?access_type=offline&response_type=code&client_id=879100301665-3hpkd1h812d5eejji8o4mku3c2ci3rcs.apps.googleusercontent.com&redirect_uri=http%3A%2F%2F127.0.0.1%3A63526%2Fauthorize%2F&scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fgmail.send" for authorization. See inner exception for details.
Second , I used to put values ​​in Programs by assigning Client ID and Client secret in Google OAuth 2 authorization.
Error
Access to the path 'C:\Windows\system32\config\systemprofile' is denied
There are a number of issues with what you are doing.
First being that you have created what appears to be a web application credentials on Google cloud console. However the code you are using GoogleWebAuthorizationBroker.AuthorizeAsync is intended for use with installed applications only. This is why you are getting the error you are getting.
The code for creating an asp .net core web app is as follows
public void ConfigureServices(IServiceCollection services)
{
...
// This configures Google.Apis.Auth.AspNetCore3 for use in this app.
services
.AddAuthentication(o =>
{
// This forces challenge results to be handled by Google OpenID Handler, so there's no
// need to add an AccountController that emits challenges for Login.
o.DefaultChallengeScheme = GoogleOpenIdConnectDefaults.AuthenticationScheme;
// This forces forbid results to be handled by Google OpenID Handler, which checks if
// extra scopes are required and does automatic incremental auth.
o.DefaultForbidScheme = GoogleOpenIdConnectDefaults.AuthenticationScheme;
// Default scheme that will handle everything else.
// Once a user is authenticated, the OAuth2 token info is stored in cookies.
o.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
})
.AddCookie()
.AddGoogleOpenIdConnect(options =>
{
options.ClientId = {YOUR_CLIENT_ID};
options.ClientSecret = {YOUR_CLIENT_SECRET};
});
}
The second issue you are having is that the redirect uri you are adding is not a valid URL it needs to be https:// at the very least you are missing the //. As well as the fact that the client library will be sending the request using /signin-google
So a proper redirect uri should be more like this.
https://localhost:5001/signin-google
I have a YouTube video which shows How to get a Google users profile information, with C#. with a companion blog post Asp .net core 3 and Google login both should work fine with .net 5 as well.

How to do Authentication & Authorization Azure AD App, using C# WEBAPI (token based) .netcore

I am able to Do Authentication and Authorization for my .netcore MVC app+reactjs (Billing App)
this application will be hosted on IIS, and on the same server planning to host the .netcore Webapi
(chart App).
By using Billing App we will call the chart WebApis. NOW WebApi should be Authenticate/Authorize user based on token sent by front-end app (token-based webapi that does Authe/Autho, no another login pop-up)
Able to Generate token using postman-see img by requesting below link
https://login.microsoftonline.com/{{tenandId}}/oauth2/token
Will sent this token with the header to Web-API, which will be having the same configuration of Azure AD app (client id, scope, etc.) as Billing App has.
Api should validate the token and send the chart data.
Should try adal/msal in reactjs so and decorate WebApis with Authorize attribute so that will take care of Authentication & Authorization?
Got many link but few code aren't working and few process is no more works for Azure, and few are having huge code and not what exactly I am looking for.
Basically I'll host one App in .netcore that does Auth part, now the WebApi should also be Auth using same user cookies/token because I don't wanna give another login popup, see lot of MS sample code but no luck
Which approach is right 1 or 2, and share sample code/link any help appreciated,
Per my understanding, you have a client app named Billing App will login users and call APIs via user based access token.
If so , you should register two apps,a client app for Billing App and a service side App .For the client app , as this is a client side, you should use users' credentials to obtain taken from Azure AD instead of app Client secrets. To implement this , you should config it as a public client on Azure AD and enable access token and ID token :
As you want to get call APIs of service side App, you should grant permissions below to make sure that users can get access token via your client app(lets assume "stanapitest" here is the service side App) :
Note, pls click Grant admin consent for Devchat button to finish the permission grant flow.
With this process done , you can get user based access token by password flow :
or OAuth2 grant code flow or Oauth2 implicit grant flow , based on your requirement of course.
Ok, its time for service side, to demo the .net core Api , let's create a simple .net core Api project in VS :
After the project created , change the client id as your service app id :
Run the project and call an API of it , as you can see it has been protected by Azure AD :
Use the user based access token to call this API :
As you can see it works as excepted . Hope it helps . If you have any further concerns , pls feel free to let me know .
After authenticating in Billing app , when you want to acquire access token to access your another web api application , you can call using the acquireTokenSilent method(msal.js) which makes a silent request(without prompting the user with UI) to Azure AD to obtain an access token. The Azure AD service then returns an access token containing the user consented scopes to allow your app to securely call the API.
It's better to make your web api as independent resource which protected by AAD , In your front-end react app , you can use acquireTokenSilent to acquire token for accessing web api after user login :
// if the user is already logged in you can acquire a token
if (msalInstance.getAccount()) {
var tokenRequest = {
scopes: ["user.read", "mail.send"]
};
msalInstance.acquireTokenSilent(tokenRequest)
.then(response => {
// get access token from response
// response.accessToken
})
.catch(err => {
// could also check if err instance of InteractionRequiredAuthError if you can import the class.
if (err.name === "InteractionRequiredAuthError") {
return msalInstance.acquireTokenPopup(tokenRequest)
.then(response => {
// get access token from response
// response.accessToken
})
.catch(err => {
// handle error
});
}
});
} else {
// user is not logged in, you will need to log them in to acquire a token
}

Categories

Resources