Identityserver4: Access denied when permission of app to my application is denied with google authentication in asp.net core

Created on 20 Apr 2017  路  21Comments  路  Source: IdentityServer/IdentityServer4

Issue / Steps to reproduce the problem

I have created an app at google developer console and configured that with my Identityserver application URL. Identityserver4 application is built in asp.net core . I have a client set up to be authorized with that IdentityServer.
Now when i try to access a secure resource on client application, identity server redirects me to my identityserver website. There i try to authenticate via google. After logging in, google console asks for the persmission that my identityserver needs to access . If i allow there, it all works fine .
But the issue arirses when i click deny, then google console app redirects to my identity server website with error="access_denied" in querystring and my identityserver website throws exception
regarding that access denied error.

How can i handle that situation given the fact that i do not allow the application to access information at google ?

question

Most helpful comment

Self-referencing closure? This should work for any of the providers.

            var fbOptions = new FacebookOptions
            {
                AppId = Configuration["facebook:appid"],
                AppSecret = Configuration["facebook:appsecret"],
                Scope = { "email" },
                Fields = { "name", "email" },
                SaveTokens = true,
            };
            fbOptions.Events = new OAuthEvents()
            {
                OnRemoteFailure = ctx =>
                {
                    var authProperties = fbOptions.StateDataFormat.Unprotect(ctx.Request.Query["state"]);
                    // do something
                    ctx.HandleResponse();
                    return Task.FromResult(0);
                }
            };
            app.UseFacebookAuthentication(fbOptions);

All 21 comments

You have to check for the error query string in your external login callback action.

When i deny persmission to app, google app console returns to my Identityserver website with url

https://localhost:44398/signin-google?error=access_denied&state=CfDJ8NAu2n0O......
and it throws exception.

External login callback action is not being called in this scenario.
Below is snapshot of error i am getting.
Please have a look and let me know if i need to share anything else .

exception-googleauth

This is something you need to handle yourself because you're writing the code to use google. What you need to do is independent of your use of IdentityServer (meaning if you build a separate MVC app that used google you'd still need to do the same thing).

I have been following IdentityServer 4 tutorials for intergrating google auth with identity server.
I tried adding a custom function that will be basically the callback url from google.
However it has the same eror as in the snapshot above.
I have gone through lots of search regarding issue. But nothing positive as yet.

I have also tested it with separate mvc application with Google auth and it worked fine even when i denied permissions.
When i deny in that case, it simply redirects back to login page.

Any idea on how it should be handled ?

IIRC you need to handle the authentication failed event on the google middleware.

I have managed to handle the access_denied case . There is an event in Google auth events that is raised when there is an error. But now i need to access client details in that event so that i can use them to construct the return url.
There is also a state parameter in query string. Can that be used for getting client information ?

How should i proceed with it ?

Check the authentication properties in the event - IIRC that should include the return URL - which in turn has all the information about the original authentication request.

I have attached the class that is being used when i get access_denied.

Please have a look and let me know if there is something i need to look at.

event-class.txt

Sure - but what's on State?

this is what is returned when i deny permission to app

https://localhost:44398/signin-google?error=access_denied&state=CfDJ8NAu2n0OEXhCqr-wzhATT2kepLaJJuoZWWmgnyzCo6UyhsmNJFiDIFf5YkRfwrTjd1Q8HxI9hodlSusQqMR-bLEa4wfgWZJKLkPRq8MR-Ac5e-77KxPX9ouSdRSz0JrsYBfSeFbZWaJ01SJaT6O14RDXed8llLaBSAXc1yfuo3PeD6kfLdJNuyq4oMCxvQHxxbqADuEMf3PzOafzxbjVVxwLptdutIQqwHSSC_tFt1nVEs0KesMABd966pjcDDEuQMhA0rhl4kTcwHAvwOWs37AE-mwkP0Rg1ZQYMakzHFQ98ik47AuyfMHOqbvGhjipqlOtJ7R0pewGvyGNDsOgqVdXPZUFzR_3NjOBLBJV1QyZirTHKTpYfnCB-iKftHBvzaDu5vpjq39GbOgpPuHn9uT-l8-tM2Y3L8lX_mXZK0cCmhtxKEt52Ky8jMw4ax-uIox8TXyCLfcszEqp6aDiiHov3El4gwXkunf8GIqWPzCk7IaFrPhS8z-ahhuWJGOFRBDz8LMFpV6JhRMysPFSun2bf706S6A4sJDqqV7A9zVetBBCEeHJ6II9FHxWiPew_1lHrUc8jvirvgHqUp4CRk8pQieLYFurWO9QyRETDz08rTVxkxiCRS6ZCadFhw6PfNdHsGSy2jUQU6XRFkuZA3vQ0AeWq9zS6pv492gIkIQ8LyXqcXO0fu3Z37OtZMRXMnO9IiHzrDuMft-iQYGBCdKiUyXKwsKfgw6131O_bHWvc1eabS7_2udPx90Djk6BTFvKx4FngXkFOGAagf5U9hUbtAznSYeyXBTsAHrCLa8M68MMBQeWd3qEIl4SQ1lIVYpZSUPGlrpFOuWRTGyx8RWZhzS7NdA8bqkcRKEuugUY1dM4996RQUkrwSHGhPRezEeY3XVeMf0UPyafZvhsjJw32aJdIym6Pr2A4p5mkasIw7BY549fz8CVBCdzfuHKvH8CqbICu7uiqTqFByZ-UkR0TtK2-TTQa8_x2fHd4th0EQo_Fcj1dsv0IZVI2GJbnqTyvUhdeNh7dvKY2BrxWUxUaBDKsThEOjrtVVPcJWCcDOC6sKBgKM_V3XZodApAzSqGT3jl2oYANxJUcXaVNUhajV23W_Xr40PoON8H0UaNn61uWH7YpDGd1ASqKZtpwSn7tY7peWeX9gL8CuOB9bDi_qFBvBnmRPXg8RX42ofnOsoHAsbq5jOW-6dsYA-sQvmbmdY4lf99jNJIsSU90KgRUtswysdzDL5ppQ8sJ859OzEMrC2ktUriscf1Y_btsIBzG5iVatKy48nYp2jHTBI#

Is there a way to basically decode the state and get the required information regarding from it
?

We took a quick look at Microsoft's source, and their plumbing is not validating state when there's an error nor surfacing it to the event handler.

We thought we could write the code to extract the state and validate it in the RemoteFailure event handler, but we ran into problems. Perhaps @tratcher might know what we are missing. We tried to do this:

app.UseGoogleAuthentication(new GoogleOptions
{
    AuthenticationScheme = "Google",
    SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme,
    ClientId = "708996912208-9m4dkjb5hscn7cjrn5u0r4tbgkbj1fko.apps.googleusercontent.com",
    ClientSecret = "wdfPY6t8H8cecgjlxud__4Gh",
    Events = new OAuthEvents
    {
        OnRemoteFailure = ctx =>
        {
            var state = ctx.Request.Query["state"].FirstOrDefault();
            if (state != null)
            {
                var options = ctx.HttpContext.RequestServices.GetRequiredService<IOptions<GoogleOptions>>();
                try
                {
                    var properties = options.Value.StateDataFormat.Unprotect(state);

                }
                catch(Exception ex)
                {

                }
            }
            return Task.FromResult(0);
        }
    }
});

But options.Value.StateDataFormat is always null so we can't attempt to extract the state. Any thoughts @tratcher? Looking thru the code, it seems that StateDataFormat is set in the middleware ctor (which seems like a bad place to modify the options object that's in DI). But anyway, it should be there -- so how is the middleware getting a non-null instance and we are?

The disconnect is that UseGoogleAuthentication(options) bypasses DI and passes that options instance directly into the middleware. It does this so you can have multiple instances of the middleware with different options.

Ok, thanks @Tratcher. So then how do you suggest @anitchanana recovers from that error from google and extract the state so they can retrieve the properties?

Self-referencing closure? This should work for any of the providers.

            var fbOptions = new FacebookOptions
            {
                AppId = Configuration["facebook:appid"],
                AppSecret = Configuration["facebook:appsecret"],
                Scope = { "email" },
                Fields = { "name", "email" },
                SaveTokens = true,
            };
            fbOptions.Events = new OAuthEvents()
            {
                OnRemoteFailure = ctx =>
                {
                    var authProperties = fbOptions.StateDataFormat.Unprotect(ctx.Request.Query["state"]);
                    // do something
                    ctx.HandleResponse();
                    return Task.FromResult(0);
                }
            };
            app.UseFacebookAuthentication(fbOptions);

@Tratcher thanks

@anitchanana I'll close this, as you will need to track on the asp.net core issue tracker.

@Tratcher ,
thanks for the help earlier.
I am trying to integrate twitter now, but when i deny app the permission , it returnes with
url?denied=mmHukAAAAAAA0Yp2AAABW7PLTo

how can i get return url from there ?

I am using this code :

twitterOptions.Events = new TwitterEvents()
{
OnRemoteFailure = ctx =>
{
var authProperties = twitterOptions.StateDataFormat.Unprotect(ctx.Request.Query["denied"]);
ctx.Response.Redirect("/Account/login");
ctx.HandleResponse();
return Task.FromResult(0);
}
};

Can you please provide me insight into this. ?

This is my code:

app.UseFacebookAuthentication(
new FacebookOptions
{
Events = new OAuthEvents
{
OnRemoteFailure = ctx =>
{
var state = ctx.Request.Query["state"].FirstOrDefault();
if (state != null)
{
var options = ctx.HttpContext.RequestServices.GetRequiredService>();
try
{
var properties = options.Value.StateDataFormat.Unprotect(state);
}
catch (Exception ex)
{
ctx.Response.Redirect("/Account/Login");
ctx.HandleResponse();
}
}
return Task.FromResult(0);
}
}
});

I have the same problem for the redirect url with ?error. I reference the way of the above and then change the redirect url in the catch. It is worked for me to link the login page when I cancel the Facebook login page.

Hi, I have created an app at Facebook developer and configured that with my Identityserver application URL. Identityserver4 application is built in asp.net core When user enter the website and connected using her Facebook my app created under Facebook developer ask him the permission to allow the app to receive her information like email adress age ... . when user cancelled the permission he is redirected to page "Account/Login" I have flowed the steps in this link : https://qawithexperts.com/questions/387/access-denied-when-permission-of-app-to-my-application-is-de

But when user accept the permissions our app ask him for another permissions (permission for managing her pages facebook "manage_page") :

here if the user decline the permissions he will redirect to Account/ExternalLoginCallback.

Actually, I need the permission from the user to collect the data from their pages, so they need to give me the autorisation to access their pages. Otherwise, we will have no data to give them. So we will redirect them to start point Account/Login means if the user accept the first permission getting the information public email and profil and decline the permissions of "manage_page" they will enforced to redirect to the start point "Account/Login"

Please how can do that Thanks. I have post my question in this link for more detail :
https://qawithexperts.com/questions/413/access-denied-when-some-permission-of-app-to-my-application
Thanks.

This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.

Was this page helpful?
0 / 5 - 0 ratings