DuendeSoftware / Support

Support for Duende Software products
21 stars 0 forks source link

authenticate using google and call remote api #1346

Closed edreux closed 2 months ago

edreux commented 3 months ago

Which version of Duende BFF are you using? 2.2.0 Which version of .NET are you using? net 8.0

Describe the Howto question In BFF, we want authenticate against google, add scopes and roles in the access token and use this access token to authenticate and authorize to our backend apis. We used this code to get the token: .AddOpenIdConnect("oidc", options => { options.Authority = "https://localhost:5001"; // builder.Configuration["ServiceUrls:IdentityServerAuthority"]; options.ClientId = "bff"; options.ClientSecret = "The Super Secret Edited"; options.ResponseType = "code"; //options.Scope.Clear(); // Calling Clear Removes openid and profile //options.Scope.Add("openid"); //options.Scope.Add("profile"); options.Scope.Add("api");
options.Scope.Add("offline_access");
options.Scope.Add("email"); options.Scope.Add(IdentityServerConstants.LocalApi.ScopeName); options.SaveTokens = true; options.MapInboundClaims = true; options.GetClaimsFromUserInfoEndpoint = true; options.TokenValidationParameters.NameClaimType = "name"; options.TokenValidationParameters.RoleClaimType = "role"; options.ClaimActions.MapJsonKey("role", "role"); options.DisableTelemetry = true; });

We used this code for connecting to the backend: app.MapRemoteBffApiEndpoint("/remote/user-token", "https://localhost:6001") .RequireAccessToken(Duende.Bff.TokenType.User);

scenario: 2 users login to google and are provisioned on the fly. user 1 gets admin role user 2 gets viewerrole Obviously, the 2 users must get different access to the backend.

To Reproduce Used and merged 2 samples: Samples-main\IdentityServer\v7\BFF\TokenExchange and Samples-main\IdentityServer\v7\BFF\JsBffSample

If we run Token Exchange and login with user alice using her username/password, it works: in the backend, we are alice. If we run JsBffSample and authenticate using Google, in the front we are the Google user (email and name are correct, role is administrator.) But when we call the backend, in the backend we are client ID bff (with google sub), we are not anymore the user. Email, name and scopes and roles that we have added are lost.

Expected behavior We want to authenticate to Google, add scopes and roles in the access token and use it to get different permissions in the backend.

For example: user 1: Name : Alice Email : alice@gmail.com TenantID : ABC123 Role: Administrator

user 2: Name : Bob Email : bob@gmail.com TenantID : ABC123 Role: Viewer

edreux commented 3 months ago

when authenticating to google, In the backend, in the controller, it crashes here: Name is not anymore in the token. ` [ [HttpGet("{**catch-all}")] public IActionResult Get() { string message; var sub = User.FindFirst("sub");

        if (!User.Identity.IsAuthenticated)
        {
            message = "Hello, anonymous caller";
        }
        else if (sub != null)
        {
            **var userName = User.FindFirst("name");**  // It crashes here, name is not anymore in token.
            message = $"Hello user, {userName.Value}";
        }
        else
        {
            var client = User.FindFirst("client_id");
            message = $"Hello client, {client.Value}";
        }

        var response = new
        {
            path = Request.Path.Value,
            message = message,
            time = DateTime.UtcNow.ToString(),
            headers = Request.Headers
        };

        return Ok(response);
    }
}`
edreux commented 3 months ago

I missed something. Actually my claims are in the ID Token, not in the access token. I wanted to add the roles in the access token in order to give different level of permissions in the backend apis.

image

RolandGuijt commented 2 months ago

The identity provider needs to be configured to include the needed claims in the access token. Assuming you're using IdentityServer, user claims can be added to access tokens by configuring the ApiScope like this:

public static IEnumerable<ApiScope> ApiScopes =>
    new ApiScope[]
    {
        new ApiScope("scope1") { UserClaims = ["role"] },
    ...

Or use the equivalent database table if your configuration is in a database. You can also set user claims on the ApiResource level.

RolandGuijt commented 2 months ago

@edreux Did this solve it for you? If so I'd like to close this issue.

edreux commented 2 months ago

you can close this issue, we've abandoned this solution.