Logout Redirect Uri für Action on Google? - identityserver4

I´m developing a action for Google, I´m using Visual Studio C' with Identity Server 4. I followed the instructions from Gooogle to create my client but now I have a question, I´ve been testing my action for a while with my client and it works very well.
new Client
{
ClientId = ApiDefinitions.ClientIdGoogle,
RedirectUris = { "https://oauth-redirect.googleusercontent.com/r/projectId"},
PostLogoutRedirectUris = {},
...(cut for readable code)
I was wondering if I am missing something in PostLogoutRedirectUris.. Does anyone knows what to give there?

For Actions on Google there isn't a logout URI as part of the OAuth flow. People are able to revoke the account linking and your auth token in the Assistant settings.

Related

Trouble authorizing access to App Engine via IAP

I currently have App Engine up and running, protected by IAP, and my eventual aim is to have this be triggered by an Apps Script project. I've tested the code without IAP and it works fine. However, I'm running into difficulties successfully authorizing access to it when IAP is enabled.
I've added myself as an IAP-secured Web App User (as well as Policy Admin) to the App Engine, but whenever I try triggering it from a GSheets Apps Script where I'm the owner and it's associated with the correct GCP project (using this great explanation as a guide) I get the following:
"Invalid IAP credentials: JWT audience doesn't match this application ('aud' claim (1084708005908-bk66leo0dnkrjsh276f0rgeoq8ns87qu.apps.googleusercontent.com) doesn't match expected value (1084708005908-oqkn6pcj03c2pmdufkh0l7mh37f79po2.apps.googleusercontent.com))"
I've tried adding/removing various permissions to my account, as well creating a new Apps Script and re-adding to the project, but to no avail. I run into the same issue when triggering from CLI, so I'm fairly sure it's an issue with authentication, however this is my Apps Script code in case it helps:
function test() {
const options = {
headers: {'Authorization': 'Bearer ' + ScriptApp.getIdentityToken()},
muteHttpExceptions: true
}
var result = UrlFetchApp.fetch('https://APP-ENGINE-URL.appspot.com', options);
Logger.log(result);
}
And the manifest file:
{
"timeZone": "Europe/London",
"dependencies": {
},
"exceptionLogging": "STACKDRIVER",
"runtimeVersion": "V8",
"oauthScopes": ["openid", "https://www.googleapis.com/auth/script.external_request"]
}
Any help on this is super appreciated! Never posted here before, but pretty desperate and couldn't find anyone with this exact problem on SO.
Consideration
The problem with your solution is that you are using the identity of an auto-generated OAuth Client for Apps Script. This clients are not suitable for this kind of authentication, here a complete list of supported OAuth clients.
Solution
In order to complete your authentication you will need an extra step. You will have to create another OAuth Client and build an identity token with its credentials.
To make things easier I would recommend to use this Apps Script library: https://github.com/gsuitedevs/apps-script-oauth2
The inital Set-up is covered in the linked documentation.
Important: When creating the OAuth Client take note of the ClientID and the Client-secret. Plus, you will need to add an Authorized Redirect URI. This is standard when using the OAuth2 GAS library and it has this form: https://script.google.com/macros/d/{Your Apps Script ID}/usercallback
Now you have all the necessary information to build your identity token. In the Github repository there is a boilerplate sample that will cover the first coding steps with the OAuth2 GAS library.
Here is the link.
Copy this code to your Apps Script project and follow the instructions in the comments. You will need to add an extra OAuth scope: "https://www.googleapis.com/auth/userinfo.email".
Once you set all the constants with your OAuth clients information you should run the run() function from your Apps Script editor. This will log a URL you have to open in your browser to authorize your App. Once you authorized the App run again the run() function and you will successfully access your IAP protected application.
References
OAuth2 GAS library
IAP programmatic authentication

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.

IdentityServer4 PostLogoutRedirectUri

I am confused about how this is used.
Most examples I've seen have it given as "/signout-callback-oidc". That seems to indicate that it uses OIDC middleware in the process. What if I want to return to a specific client page?
The automatic redirect isn't working when I set IdentityServer's AccountOptions.cs property of AutomaticRedirectAfterSignOut to true. Further, during logout, I do not receive the client's PostLogoutRedirectUri.
So, is that link supposed to go to the OIDC middleware, or is it available for use to redirect to the client?
Your client has to be configured to request the callback to one of those URIs as part of the client-initiated sign-out flow.
IS4 clients can be configured with lists of allowable redirect URIs for both sign-in and sign-out, which I'm guessing is where you see /signout-callback-oidc -- if I remember right, either the docs or maybe the Quickstart code uses that, but there's nothing special about that particular URI name. (It isn't some OIDC standard, or a "well-known" name, or anything of that nature, as far as I know.)
The missing piece of the puzzle is to configure OIDC in the client application. You didn't mention what kind of application is on the client side, but in ASP.NET Core it's an option named SignedOutCallbackPath on the AddOpenIdConnect service:
services.AddOpenIdConnect("oidc", options =>
{
options.SignInScheme = "Cookies";
options.Authority = appConfig["OidcAuthority"];
options.ClientId = appConfig["OidcClientId"];
options.ClientSecret = appConfig["OidcClientSecret"];
// etc
options.SignedOutCallbackPath = "/jake-says-goodbye";
});
This causes the OIDC implementation to add a property to the sign-out request identifying that redirect URI. As long as your application properly identifies itself, as briefly mentioned in the docs here, and as long as /jake-says-goodbye is one of the approved post-logout redirect URIs on the IS4 side, you should get the callback you're expecting.
(I specifically mention "proper" identification because, based on github questions I've seen, it sounds like it might be more difficult to manage for a JS-based SPA client app versus whatever helpful things MVC does behind the scenes to manage server-to-server OIDC interaction. I can't speak to that as I've not had a need to implement any SPA clients with IS4 yet.)
The problem is that you have to set a very specific parameter in order for the PostLogoutRedirectUri to not show up as null on IdentityServer's side, and testing any of the options results in having to step through a ton of ways to set it, most of them still resulting in null. Since I'm using an older client with IdentityServer4 (in order to enable .NET 4.x webapps to authenticate through IdentityServer4, cannot easily use .NET Core with those projects - luckily IdentityServer4 is still compatible with the older client code), the action that triggers signout has two relevant things (and you'll find a TON of examples of code for that will not work for you with MVC in .NET 4.x):
Use the signout() method in this sample github repo (the IdentityServer3 MVC Owin sample client): https://github.com/IdentityServer/IdentityServer3.Samples/blob/master/source/Clients/MVC%20OWIN%20Client/Controllers/HomeController.cs You can trigger that action from a button in a view.
That will get intercepted by the client's Owin middleware if you do this: https://github.com/IdentityServer/IdentityServer3/issues/2687#issuecomment-194739035 I didn't use the stored message bit, and I added the PostLogoutRedirectUri parameter in a way that IdentityServer4's LogoutRequest model wouldn't remove with this line in the same segment:
n.ProtocolMessage.PostLogoutRedirectUri = "http://myredirectaddress/ActionToDoOnceReturned";
You have to make sure that the above matches the client's PostLogoutRedirectUri on the IdentityServer side's client config or it'll be null again, and you would have missed it among all the other parameters. For instance, these methods of setting PostLogoutRedirectUri DO NOT work:
n.ProtocolMessage.SetParameter("PostLogoutRedirectURI", "some URL");
n.ProtocolMessage.SetParameter("PostLogoutUri", "another URL");
n.ProtocolMessage.SetParameter("PostLogoutRedirectUri", "yet another URL that's going to be ignored by IdentityServer4");
From there, you're off to the races because PostLogoutRedirectUri is no longer null. There are a few more considerations: check out AccountOptions in the IdentityServer controller folder. I set AutomaticRedirectAfterSignout to true there (this is used by Javascript in IdSrv's final logout page - if set, the script uses PostLogoutRedirectUri to forward the user back to the client). There's also an option to show a logout confirmation prompt, which if you want to actually display, make sure to NOT set the id token hint in the Owin (it's right next to where we set the PostLogoutRedirectUri / the part that gets triggered by signout requests). If you do those two things, AccountServices.BuildLogoutViewModel will return the prompt to the user when it's called by the AccountController.logout() method.
Thank you aaronR for the answer to my other question concerning that part:
IdentityServer4 logout (id token hint tells IdentityServer that the signout request was authorized and not a malicious person trying to harass your system / sign out users, IdSrv will ask the user for confirmation if it's not provided).
Finally, if you are confused by what's happening on the IdentityServer side in logout, and why it's repeatedly triggering the same method:
First time it gets called from the client's Owin middleware (the bit of code above that gets triggered after the Signout() action).
It uses AccountService to build a view model to return to the user for logout confirmation.
It gets triggered again by the user clicking yes on that page.
It goes through the Account service method again, which this time sets the bool to show the logout confirmation to false.
It calls the second logout method, the one with the view model that gets passed in.
This one triggers the external identity provider signout.
The external identity provider returns control back to logout, resulting in it getting called again, calling the second logout method again.
Finally, it will return the user to IdentityServer's logout page. If PostLogoutRedirectUri is set & AutomaticRedirectAfterSignOut is true, there's javascript on that page which automatically forwards the user's browser to it.
Due to having two projects to debug through at once and all of these possible ways of setting the redirect (which also have to match client/server side config in order not to be null) it can be easy to get confused.
Overview
When setting up IdentityServer (assuming it's a separate application), there are two parameters in the configuration for an accessing client: RedirectUris and PostLogoutRedirectUris. These correspond to what happens after a login or logout of a user against the IdentityServer system.
Since your client app probably has its own cookies (or JWT tokens, or whatever it's using to maintain a user session), it needs to know when the IdentityServer has processed the login and made the user data available.
The default ASP.NET OpenID Connect middleware does this with yourapp.com/signin-oidc and yourapp.com/signout-callback-oidc endpoints to intercept and handle the login/logout hand-off from IdentityServer. These endpoints have nothing to do with the OpenID protocol and can be set to whatever you want if you have your own authentication handler, but if you're using the default middleware then you must set them to that in the IdentityServer config.
Config option
However, if you still want to redirect a user after the OpenID Connect logout has completed, there's an option specifically for this:
services.AddOpenIdConnect(options =>
{
// your other options...
options.SignedOutRedirectUri = "/some-page-after-oidc-logout";
});
Microsoft Docs
I want to share how I solved problem with null PostLogoutRedirectUri value.
I always had null PostLogoutRedirectUri value in logout context until I added SignInScheme value on mvc client side.
These settings of authentication on MVC client side works for me:
var authenticationBuilder = services.AddAuthentication(options =>
{
options.DefaultScheme = "Cookies";
options.DefaultChallengeScheme = "oidc";
});
authenticationBuilder.AddCookie(options =>
{
options.ExpireTimeSpan = TimeSpan.FromMinutes(60);
options.Cookie.Name = "identity_server_mvc";
});
authenticationBuilder.AddOpenIdConnect("oidc", options =>
{
options.Authority = "{IDENTITY_SERVER_URL}";
options.ClientId = "mvc";
options.SaveTokens = true;
options.SignInScheme = "Cookies";
});
You also need to make sure that you have added the PostLogoutRedirectUri value to the client configuration on the Identity Server side:
new Client
{
ClientId = "mvc",
AllowedGrantTypes = GrantTypes.Implicit,
RedirectUris = { "{CLIENT_URL}/signin-oidc" },
PostLogoutRedirectUris = { "{CLIENT_URL}/signout-callback-oidc" },
AllowedScopes =
{
IdentityServerConstants.StandardScopes.OpenId,
IdentityServerConstants.StandardScopes.Profile
}
}
One last but important point, because of this I had null logoutId value on Identity Server side. To initiate Logout process you must first call SignOut("Cookies", "oidc") on mvc client side. Example endpoint in my HomeController:
public IActionResult Logout()
{
return SignOut("Cookies", "oidc");
}
Good luck!
Building on top of #McGuireV10 answer if your project is a Blazor WASM, then the change would be like this:
// Adds OpenID Connect Authentication
builder.Services.AddOidcAuthentication(options =>
{
options.ProviderOptions.Authority = settings.Authentication.Authority;
options.ProviderOptions.ClientId = settings.Authentication.ClientId;
options.ProviderOptions.ResponseType = "code";
options.ProviderOptions.ResponseMode = "query";
//
options.AuthenticationPaths.LogOutCallbackPath = "authentication/logout-callback";
builder.Configuration.Bind("oidc", options.ProviderOptions);
});
I ran into the same issue today; your (#JakeJ) link solved it for me. I am building a demo MVC Owin Client in .net 4.6.1 (for a third party company) so our set up is the same and our Id Svr v4 is built on net core v3.1.
I verified i had the same PostLogoutRedirectUri defined in the Id Svr side config for the client i was working on and then at the client side config too.
But i noticed that i could add a small block of code taken from the ref'ed github issue to the RedirectToIdentityProvider func delegate specific to logout.
if (n.ProtocolMessage.RequestType == OpenIdConnectRequestType.Logout)
{
// below is technically not needed, as it was already set for me.
n.ProtocolMessage.PostLogoutRedirectUri = LoginAndOutRedirectUri;
var idTokenHint = n.OwinContext.Authentication.User.FindFirst("id_token").Value;
n.ProtocolMessage.IdTokenHint = idTokenHint;
}
This means that a claim needs to be present in order for this to work so i then added the below to the SecurityTokenValidated func delegate:
// add id token for logout
currentIdentity.AddClaim(new Claim("id_token", n.ProtocolMessage.IdToken));
I saw many examples where folks were populating the AuthenticationTicket inside the AuthorizationCodeReceived func delegate but for me it was always null. So some head scratching lead me to implementing what i needed inside the SecurityTokenValidated delegate. And it all works and hands together nicely.

C# .NetCore Okta Search for Users

I am trying to figure out how to search for users in Okta using the SDK and .net core in C#. outside of .net core I am able to do this using Okta.Core but that is not supported in .NET Core. I can't find any documentation for doing this stuff in .NetCore using the SDK.
I can get the OktaClient connected no problem with my API token but after that I am lost now.
Anyone have an example of doing this in Core or can point me in the right direction to get documentation from Okta?
Looking thought the Okta documentation I found the below code, where the client is the Okta client. Hopefully this helps:
Getting A User
// have some user's ID, or login
var someUserId = "<Some User ID String or Login>";
// get the user with the ID or login
var vader = await client.User.GetUserAsync(someUserId);

google app script consumer with google appEngine Provider (Oauth)

I could get an Oauth conexion between GAS and GAE.
I built a Google Gadget which needs some data from my datastore application, it has 3 end points to finally get an access token.
http//[myapp].appspot.com/_ah/OAuthGetRequestToken
http//[myapp].appspot.com/_ah/OAuthAuthorizeToken
http//[myapp].appspot.com/_ah/OAuthGetAccessToken
In GAS side i have the tipical function to get an access token.
function oauthTokenFetch(){
var oAuthConfig = UrlFetchApp.addOAuthService("myAppName");
oAuthConfig.setAccessTokenUrl("https://<myApp>appspot.com/_ah/OAuthGetAccessToken");
oAuthConfig.setRequestTokenUrl("https://<myApp>.appspot.com/_ah/OAuthGetRequestToken");
oAuthConfig.setAuthorizationUrl("https://<myApp>.appspot.com/_ah/OAuthAuthorizeToken");
oAuthConfig.setConsumerKey("<myApp>.appspot.com");
oAuthConfig.setConsumerSecret("myConsumerSecret");
var requestData = {
"method": "GET",
"oAuthServiceName": "myAppName",
"oAuthUseToken": "always"
};
try {
var response2=UrlFetchApp.fetch("http://<myApp>.appspot.com/test/oauth",requestData);
Logger.log(response2.getResponseCode());
}catch(exception){
Logger.log(exception);
}
If i revoked the access token on google accounts, it isn't able for getting another one, the popup which grants the authorization don't appears ... i have to copy the google gadget and do the authorization again.
Somebody have a Solution?
There currently isn't a method to allow you to revoke or remove an OAuth token in a script. It looks like you already filed a bug/feature request on the topic, and we'll follow up there.

Resources