Open Closed

Loging and accessing the Web API from another client #3411


User avatar
0
Leonardo.Willrich created

If you're creating a bug/problem report, please include followings:

  • ABP Framework version: v5.3
  • UI type: Blazor WASM
  • DB provider: EF Core

Hi,

I'm building another Web Application in Blazor WebAssembly PWA that will just trigger some actions from my main web page application. It is not using ABP.IO framework, it is just a simple application.

To call methods from Web API, I know that I can request the Token using /access/token and using the Identity Server client details. Then, when calling the method using HttpClient, I have to add the "__tenant" and "Authorization" with "Bearer {access_token}" in the Header.

Questions:

  1. In the application service, the Current User is always Null.
  2. How can I use Dynamic API Clients using the module HttpApi.Client? Is there some example? (https://docs.abp.io/en/abp/latest/API/Dynamic-CSharp-API-Clients)
  3. I need to check the user permissions on the application side, how I can do that properly?
  4. In Post methods it is a return error related to AntiForgery ([15:57:46 ERR] The required antiforgery cookie ".AspNetCore.Antiforgery.VzbPRCldIbQ" is not present.). What is missing? Do you have an example of calling a Post method using Postman?

Kind regards,

Leonardo Willrich.


29 Answer(s)
  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    1In the application service, the Current User is always Null.

    Please share your access_token and API authentication configuration code.

    2 How can I use Dynamic API Clients using the module HttpApi.Client?

    You need to bootstrap the ABP module system and dependencies related modules

    3 I need to check the user permissions on the application side, how I can do that properly?

    You can get configuration from api/abp/application-configurationendpoint.

    4 In Post methods it is a return error related to AntiForgery ([15:57:46 ERR] The required antiforgery cookie ".AspNetCore.Antiforgery.VzbPRCldIbQ" is not present.). What is missing? Do you have an example of calling a Post method using Postman?

    Try to remove cookies from your PostMan request.

  • User Avatar
    0
    Leonardo.Willrich created

    I'll send you the details tomorrow. Do you have any examples of your answer? For example, how can I use api/abp/application-configuration.

  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    how can I use api/abp/application-configuration.

    Just make an HTTP request and serializable response JSON to ApplicationConfigurationDto

    https://github.com/abpframework/abp/blob/dev/framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ApplicationConfigurationDto.cs#L9

  • User Avatar
    0
    Leonardo.Willrich created

    Hi Maliming,

    Requesting the token like this. In the Header, I've added the key "__tenant" with the tenant name.

    Here is the token generated:

    eyJhbGciOiJSUzI1NiIsImtpZCI6IjYyM0RCMjY5MThBRUNGMTcwRjYzMTk3RkJEQTQwNUVBIiwidHlwIjoiYXQrand0In0.eyJuYmYiOjE2NTc2OTU2NzAsImV4cCI6MTY4OTIzMTY3MCwiaXNzIjoiaHR0cHM6Ly9sb2NhbGhvc3Q6NDQzNjQiLCJhdWQiOiJTQkMiLCJjbGllbnRfaWQiOiJTQkNfTW9iaWxlIiwic3ViIjoiMzlmY2UyNjctNjkxYi0wMDVkLTI2ODgtNDJmZTgyNzg5MzM4IiwiYXV0aF90aW1lIjoxNjU3Njk1NjcwLCJpZHAiOiJsb2NhbCIsInRlbmFudGlkIjoiMzlmY2UyNWItMmIzNy1jM2ZlLTIyODUtNjlhZDQ3MWM0ZmZlIiwicm9sZSI6ImFkbWluIiwicGhvbmVfbnVtYmVyIjoiKzY0Mjc1ODc0Mjk1IiwicGhvbmVfbnVtYmVyX3ZlcmlmaWVkIjoiRmFsc2UiLCJlbWFpbCI6Imxlb25hcmRvLndpbGxyaWNoQHR2ZC5jby5ueiIsImVtYWlsX3ZlcmlmaWVkIjoiVHJ1ZSIsImVkaXRpb25pZCI6IjM5ZmNlMjU5LTViNGEtZmFjNi1iYzU2LWY3OGEyN2RlMmUyZiIsIm5hbWUiOiJsZW8iLCJpYXQiOjE2NTc2OTU2NzAsInNjb3BlIjpbImFkZHJlc3MiLCJlbWFpbCIsIm9wZW5pZCIsInBob25lIiwicHJvZmlsZSIsInJvbGUiLCJTQkMiLCJvZmZsaW5lX2FjY2VzcyJdLCJhbXIiOlsicHdkIl19.CTIS5YyRvFigvPN8qPboDzQg8DeKogy-SBTRJMrTL7hZiYCYRR9sv4nsHTrMNDgLJf8IJf-Tq4RJ-XmM4ZsnFhGxXsiXdCiHfAIo0QJJ_TVNgwazUWDk6wakIpCppH0dlGa2vayTQc882lvflTutxgbfNiRdDJ5_mKEAmgb1XuVGRu6GHig-tpXHrUp_R-GzistEV8IaHppErDjHtcAdyTPtBUpZsRUxPDSeAJylZZScRxT_IUHKA2BigzY3MkbYDgfcfAew7En6QGpK0jE3FBU7UIQfsINf6QJTAXNA4WuvOzhNVovBKHdormwSHBWTOmBEkxgpBZZko4iKM4_68A

    If I try to call a method from my API, passing the token in Authorization and the __tenant, the CurrentUser will be NULL.

    I've follow also the steps from this post in the community, but, also the CurrentUser is null.

    How can I set the Current User? It is quite important in my methods as I am filtering data based on the Current User Id. I don't want to have two methods, one for my website and another one for other applications calling the API method.

    Thank you!

  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    If I try to call a method from my API, passing the token in Authorization and the __tenant, the CurrentUser will be NULL.

    Can you share the request info(Authorization: bearer token) and the authentication configuration code of your API(context.Services.AddAuthentication(....))?

  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    You can set a breakpoint to check the claims for the current identity(HttpContext.User).

  • User Avatar
    0
    Leonardo.Willrich created

    Hi maliming,

    I've found that the CurrentUser is not NULL at all, actually, only the Name and Surname are null.

    See the CurrentUser object:

    {
      "IsAuthenticated": true,
      "Id": "39fce267-691b-005d-2688-42fe82789338",
      "UserName": "leo",
      "Name": null,
      "SurName": null,
      "PhoneNumber": "+64275874295",
      "PhoneNumberVerified": false,
      "Email": "leonardo.willrich@tvd.co.nz",
      "EmailVerified": true,
      "TenantId": "39fce25b-2b37-c3fe-2285-69ad471c4ffe",
      "Roles": [
        "admin"
      ]
    }
    
    

    I've found it on this topic in Github: https://github.com/abpframework/abp/issues/6571

  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    hi

    What's the type of the AbpClaimTypes.Nameand AbpClaimTypes.SurName?

    Check the claims of HttpContext.User and set the types. AbpClaimTypes.Name = xx

  • User Avatar
    0
    Leonardo.Willrich created

    Hi Maliming,

    I got a bit confused now. Where can I check HttpContext.User and where I can set the types exactly?

    See if this image answers your question:

  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    You can check the HttpContext.User in your page/controller.

    If the AbpClaimTypes.Name not match the type in User you can change it AbpClaimTypes.Name = xx

  • User Avatar
    0
    Leonardo.Willrich created

    Hi,

    I'm still struggling to create the application and create a decent login system for it.

    How can I validate and refresh a token? Currently, I'm saving the date/time expiration in the session. If that is expired, I'm trying to call connect/introspect, but, no success. Same error as described on this item: https://github.com/abpframework/abp/issues/12394

    I've tried to use refresh_token grant_type, as per IdentityServer4 documentation, but, it is also not working. It is saying Grant is invalid. Besides, there is no refresh_token token in the Identity Server > Client form. I had to add a custom grant type.

  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    hi

    How can I validate and refresh a token? Currently, I'm saving the date/time expiration in the session. If that is expired, I'm trying to call connect/introspect, but, no success. Same error as described on this item: https://github.com/abpframework/abp/issues/12394

    Did you add a secret to the client?

    https://github.com/abpframework/abp/issues/12394#issuecomment-1112961398

    It is saying Grant is invalid. Besides, there is no refresh_token token in the Identity Server > Client form. I had to add a custom grant type.

    What is your request? You can use the IdentityModel class library. https://identitymodel.readthedocs.io/

  • User Avatar
    0
    Leonardo.Willrich created

    Yes, I have a secret in my client. I'm using the IdentityModel class library.

    Here is my method to Introspect the token:

     public async Task<bool> ValidateToken(string accessToken)
            {
                Console.WriteLine("ValidateToken Init");
                var authority = _baseUrl;
                var discoveryCache = new DiscoveryCache(authority);
                var disco = await discoveryCache.GetAsync();
                var httpClient = new Lazy<HttpClient>(() => new HttpClient());
                Console.WriteLine("ValidateToken 1");
                var response = await httpClient.Value.IntrospectTokenAsync(new TokenIntrospectionRequest
                {
                    Address = disco.IntrospectionEndpoint,
                    ClientId = "xxx",
                    ClientSecret = "xxx",
                    Token = accessToken,
                });
                Console.WriteLine("ValidateToken 2 - response: {0}", JsonSerializer.Serialize(response));
                return !response.IsError && response.IsActive;
            }
    

    There are two things that I notice wrong:

    1. It uses the ClientId to check the API Resource Id;
    2. Even adding a secret to my API resource and changing the ClientId to the same Id as the Api Resource, it fails.

    Here are the logs when the ClientId is the API Resource ID:

    [14:37:27 INF] Request starting HTTP/2 POST https://localhost:44364/connect/introspect application/x-www-form-urlencoded 1201
    [14:37:27 INF] CORS policy execution successful.
    [14:37:27 DBG] CORS request made for path: /connect/introspect from origin: https://localhost:7044 but was ignored because path was not for an allowed IdentityServer CORS endpoint
    [14:37:27 INF] No CORS policy found for the specified request.
    [14:37:27 DBG] Request path /connect/introspect matched to endpoint type Introspection
    [14:37:27 DBG] Endpoint enabled: Introspection, successfully created handler: IdentityServer4.Endpoints.IntrospectionEndpoint
    [14:37:27 INF] Invoking IdentityServer endpoint: IdentityServer4.Endpoints.IntrospectionEndpoint for /connect/introspect
    [14:37:27 DBG] Starting introspection request.
    [14:37:27 DBG] Start parsing Basic Authentication secret
    [14:37:27 DBG] Start parsing for secret in post body
    [14:37:27 DBG] Parser found secret: PostBodySecretParser
    **[14:37:27 DBG] Secret id found: SBC**
    [14:37:27 DBG] No shared secret configured for client.
    [14:37:27 DBG] Secret validators could not validate secret
    [14:37:27 INF] {"ApiName": "SBC", "Category": "Authentication", "Name": "API Authentication Failure", "EventType": "Failure", "Id": 1021, "Message": **"Invalid API secret"**, "ActivityId": "40000025-0006-cc00-b63f-84710c7967bb", "TimeStamp": "2022-07-15T02:37:27.0000000Z", "ProcessId": 35360, "LocalIpAddress": "::1:44364", "RemoteIpAddress": "::1", "$type": "ApiAuthenticationFailureEvent"}
    [14:37:27 ERR] API validation failed.
    [14:37:27 ERR] API unauthorized to call introspection endpoint. aborting.
    [14:37:27 INF] Request finished HTTP/2 POST https://localhost:44364/connect/introspect application/x-www-form-urlencoded 1201 - 401 - - 11.6988ms
    

    Here are the logs the ClientId is the ClientId indeed:

    [14:38:51 DBG] CORS request made for path: /connect/introspect from origin: https://localhost:7044 but was ignored because path was not for an allowed IdentityServer CORS endpoint
    [14:38:51 INF] No CORS policy found for the specified request.
    [14:38:51 DBG] Request path /connect/introspect matched to endpoint type Introspection
    [14:38:51 DBG] Endpoint enabled: Introspection, successfully created handler: IdentityServer4.Endpoints.IntrospectionEndpoint
    [14:38:51 INF] Invoking IdentityServer endpoint: IdentityServer4.Endpoints.IntrospectionEndpoint for /connect/introspect
    [14:38:51 DBG] Starting introspection request.
    [14:38:51 DBG] Start parsing Basic Authentication secret
    [14:38:51 DBG] Start parsing for secret in post body
    [14:38:51 DBG] Parser found secret: PostBodySecretParser
    **[14:38:51 DBG] Secret id found: SBC_Mobile**
    [14:38:51 INF] {"ApiName": "SBC_Mobile", "Category": "Authentication", "Name": "API Authentication Failure", "EventType": "Failure", "Id": 1021, "Message": **"Unknown API resource", **"ActivityId": "400000eb-0008-f200-b63f-84710c7967bb", "TimeStamp": "2022-07-15T02:38:51.0000000Z", "ProcessId": 35360, "LocalIpAddress": "::1:44364", "RemoteIpAddress": "::1", "$type": "ApiAuthenticationFailureEvent"}
    [14:38:51 ERR] No API resource with that name found. aborting
    [14:38:51 ERR] API unauthorized to call introspection endpoint. aborting.
    [14:38:51 INF] Request finished HTTP/2 POST https://localhost:44364/connect/introspect application/x-www-form-urlencoded 1208 - 401 - - 21.0535ms
    
  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    hi

    Can you share a simple project to reproduce? liming.ma@volosoft.com

  • User Avatar
    0
    Leonardo.Willrich created

    Yes, I can do it. Just need a few minutes to create it and will email you.

    Another thing that I found. If I update a Client (just edit, change some field, can save), it doesn't work anymore. It says that the secret is invalid. Looking at the database, table IdentityServerClientSecrets, I found that the column "Value" was modified and it has the same value as the previous record. Can you have a look at that as well?

  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    Another thing that I found. If I update a Client (just edit, change some field, can save), it doesn't work anymore. It says that the secret is invalid. Looking at the database, table IdentityServerClientSecrets, I found that the column "Value" was modified and it has the same value as the previous record. Can you have a look at that as well?

    Does this resolve the problem? https://support.abp.io/QA/Questions/3404#answer-5bd6d8f3-7f01-53fa-6050-3a05049ffeee

  • User Avatar
    0
    Leonardo.Willrich created

    Another thing that I found. If I update a Client (just edit, change some field, can save), it doesn't work anymore. It says that the secret is invalid. Looking at the database, table IdentityServerClientSecrets, I found that the column "Value" was modified and it has the same value as the previous record. Can you have a look at that as well?

    Does this resolve the problem? https://support.abp.io/QA/Questions/3404#answer-5bd6d8f3-7f01-53fa-6050-3a05049ffeee

    Yes, it seems that worked. Cheers!

  • User Avatar
    0
    Leonardo.Willrich created

    hi

    Can you share a simple project to reproduce? liming.ma@volosoft.com

    I've sent a Windows Form project. Just change the fields using your remote server with a valid client.

  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer
    
    var testClientId = configurationSection["SBC_Mobile:ClientId"];
    if (!testClientId.IsNullOrWhiteSpace())
    {
        await CreateClientAsync(
            name: testClientId,
            scopes: commonScopes,
            grantTypes: new[] { "password", "client_credentials", "authorization_code"},
            secret: configurationSection["SBC_Mobile:ClientSecret"].Sha256(),
            requireClientSecret: true,
            redirectUri: "https://localhost:44317"
        );
    }
            
    private async Task<ApiResource> CreateApiResourceAsync(string name, IEnumerable<string> claims)
        {
            var apiResource = await _apiResourceRepository.FindByNameAsync(name);
            if (apiResource == null)
            {
                apiResource = await _apiResourceRepository.InsertAsync(
                    new ApiResource(
                        _guidGenerator.Create(),
                        name,
                        name + " API"
                    ),
                    autoSave: true
                );
            }
    
            foreach (var claim in claims)
            {
                if (apiResource.FindClaim(claim) == null)
                {
                    apiResource.AddUserClaim(claim);
                }
            }
    
            if (apiResource.FindSecret((name + "Secret").Sha256()) == null)
            {
                apiResource.AddSecret((name + "Secret").Sha256());
            }
    
            return await _apiResourceRepository.UpdateAsync(apiResource);
        }
    
    Scope = "email openid profile offline_access role phone address SBC",
    
    var response = await httpClient.Value.IntrospectTokenAsync(new TokenIntrospectionRequest
    {
        Address = disco.IntrospectionEndpoint,
        ClientId = "SBC",
        ClientSecret = "SBCSecret",
        Token = token.Text,
    });
    
    var response = await httpClient.Value.RequestRefreshTokenAsync(new RefreshTokenRequest()
    {
        Address = disco.TokenEndpoint,
        ClientId = clientId.Text,
        ClientSecret = secret.Text,
        RefreshToken = refreshToken.Text,
    });
    

  • User Avatar
    0
    Leonardo.Willrich created

    Hi Maliming,

    For Introspect it is working fine. But, for RefreshToken it is saying the grant_type is invalid. Have you managed to make it work?

  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    Check the endpint and refresh token

  • User Avatar
    0
    Leonardo.Willrich created

    If I use refreshToken.Text, which is empty, it will raise this exception:

    System.ArgumentException: Parameter is required (Parameter 'refresh_token')

    Endpoint is exactly the same. Here is my code:

    var response = await httpClient.Value.RequestRefreshTokenAsync(new RefreshTokenRequest()
    {
        Address = disco.TokenEndpoint,
        ClientId = clientId.Text,
        ClientSecret = secret.Text,
        RefreshToken = refreshToken.Text,
    });
    
  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    You can save the refresh token when calling the request token. it will both return the access token and refresh token.

  • User Avatar
    0
    Leonardo.Willrich created

    I got it. But, RefreshToken property is null in the response of Request Token:

  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    Add offline_access to the scopes.

Made with ❤️ on ABP v8.2.0-preview Updated on March 25, 2024, 15:11