Base solution for your next web application
Open Closed

httponly cookies #12191


User avatar
0
aiqbal created

I have followed the guide on this page, https://aspnetzero.com/blog/http-only-cookies-in-asp.net-zero-angular-ui, to support secure httponly cookies but I'm running into issues and I suspect it's because we are not using multi tenancy.

When running the project on the server it will not go beyond the login page. There are no errors on the console or network. It will simply redirect us back to the login page after logging in.

The only difference I can see from before and after making the change is that when it's calling /AbpUserConfiguration/GetAll the response coming back is missing data compared to what we had before. In the past the session section would have the userId but now it comes back as null. The theme information coming back is also different. I think it's coming back with the default values.

If we try to run the project locally, with IsHttpOnlyCookieEnabled set to false in the appsettings.json, we also ran into problems. In this case we could login but it would always take us to /app route while loading an improper theme. We found that we could fix this particular issue by ignoring the part of the guide where it wants to change getUserConfiguration() to stop setting the requestHeaders when calling /AbpUserConfiguration/GetAll. Adding the header back in at least fixed the behaviour locally.

Any ideas on how to fix this? We need to fix this within the next week for security reasons so any help would be appreciated.

<br>

private static getUserConfiguration(callback: () => void): any {
    let requestHeaders = AppPreBootstrap.getRequetHeadersWithDefaultValues();

    if(!abp.auth.isHttpOnlyCookieEnabled){
        const token = abp.auth.getToken();

        if (token) {
            requestHeaders['Authorization'] = 'Bearer ' + token;
        }
    }

    return XmlHttpRequestHelper.ajax(
        'GET',
        AppConsts.remoteServiceBaseUrl + '/AbpUserConfiguration/GetAll',
        requestHeaders, //the guide wants to set this line to null but it causes issues
        null,
        (response) => {
            let result = response.result;

            _merge(abp, result);

            abp.clock.provider = this.getCurrentClockProvider(result.clock.provider);

            AppPreBootstrap.configureLuxon();

            abp.event.trigger('abp.dynamicScriptsInitialized');

            AppConsts.recaptchaSiteKey = abp.setting.get('Recaptcha.SiteKey');
            AppConsts.subscriptionExpireNootifyDayCount = parseInt(
                abp.setting.get('App.TenantManagement.SubscriptionExpireNotifyDayCount')
            );

            DynamicResourcesHelper.loadResources(callback);
        }
    );

15 Answer(s)
  • User Avatar
    0
    m.aliozkaya created
    Support Team

    Hi @aiqbal,

    First of all, your backend project and your Angular project must be located in the same domain. For example, if your Angular project is located in https://localhost:44300. Then your backend project *.Host must be located in https://localhost:44300/api.

    Does your project comply with the rules mentioned above?

  • User Avatar
    0
    aiqbal created

    They do locally, but we are more concerned about what happens when we deploy to the server. In that case the angular website is hosted at admin.ourdomain.com and the api is located at api.ourdomain.com.

  • User Avatar
    0
    m.aliozkaya created
    Support Team

    Hi @aiqbal,

    After the Angular build, you can move the dist folder items to *.Host/wwwroot. Then go wwwroot/assets/appconfig.production.json update "appBaseUrl": "https://localhost:44301", Then you can test it locally.

    The theme I selected before is installed successfully.

  • User Avatar
    0
    aiqbal created

    Hi. We have tried this but it did not work for us. Just to confirm are you running in single tenancy mode?

    The theme/session issue mentioned is something we are seeing happening if we set IsHttpOnlyCookieEnabled to false but that isn't the important issue at the moment since we want to use the httponly cookie.

    When we set IsHttpOnlyCookieEnabled to true then we cannot proceed past the login screen. We can see that it authenticated successfully but the user is forwarded back to the login screen right after. Do you know why this could be happening?

  • User Avatar
    0
    m.aliozkaya created
    Support Team

    Hi @aiqbal,

    I disabled the multi-tenancy and tested again. It is still working correctly.

    Could you check the cookies?

    Also, can you check the response header

    You can review your codes from the sample project. https://github.com/aspnetzero/aspnet-zero-samples/tree/master/AngularHttpOnlyCookieDemo

  • User Avatar
    0
    aiqbal created

    Hi,

    We downloaded the sample project on github. We enabled IsHttpOnlyCookieEnabled and tried running it but we are still seeing the same issue where the user logs in successfully but then ends up back on the login page. This was with the AngularHttpOnlyCookieDemo sample project.

    The login process is working correctly. We can see the cookies being set.

    But then in the follow up http calls there is no auth token being attached to the header of the requests. If we try with IsHttpOnlyCookieEnabled set to false then we see that the follow up calls do have the additional header value so we suspect this is the issue.

    In your example I'm seeing that you're running everything under localhost but in our case the api and angular project are in the same domain, but different sub domains. For example api.domain.com and angular.domain.com. Could you confirm that this scenario works for you?

  • User Avatar
    0
    m.aliozkaya created
    Support Team

    Hi @aiqbal,

    It seems you need to configure the domain path. You can use the cookies between subdomains. https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies#define_where_cookies_are_sent

    Is your problem occurring in production? Does it work properly on localhost?

  • User Avatar
    0
    aiqbal created

    Hi,

    We are trying this on our development server. We tried setting the domain as well. We set it to ".ourdomain.com" on the c# side when creating the cookies and we can see that the cookies have the correct domain on the browser side in the /authenticate response, but the issue persists in follow up calls where the auth header is not being sent.

    ~~I see that cookies are also set on the angular side in the abp.js file but I don't see a way to set the domain in there. I'm referring to the abp.utils.setCookieValue lines. Do you know how you would go about setting the domain there? We could try that.~~ On second look we do see a way to set the domain property in the abp.js file. We tried this but it did not make a difference.

    As for running it locally to see it working; we aren't sure how you're managing to run both the api and the angular project in the same port. If you could explain how to configure that we can try it to rule that out.

  • User Avatar
    0
    m.aliozkaya created
    Support Team

    Hi,

    We use this middleware to add request headers to Abp.AuthToken. https://github.com/aspnetzero/aspnet-zero-samples/blob/master/AngularHttpOnlyCookieDemo/aspnet-core/src/AngularHttpOnlyCookieDemo.Web.Host/Startup/HttpOnlyMiddleware.cs

    Could you check these lines? Could there be an error in the middleware order? https://github.com/aspnetzero/aspnet-zero-samples/blob/de188c79948061b482f085a95aed142ead4d8c76/AngularHttpOnlyCookieDemo/aspnet-core/src/AngularHttpOnlyCookieDemo.Web.Host/Startup/Startup.cs#L203

  • User Avatar
    0
    aiqbal created

    Hi,

    We checked and the middleware is configured correctly. The issue is that the header is not being sent in by the angular side.

    Could you explain how you got the api and angular side to work under the same port in localhost for AngularHttpOnlyCookieDemo so that we can see the login process working correctly locally. Perhaps that would give us some clues about what is different in our setup.

  • User Avatar
    0
    m.aliozkaya created
    Support Team

    Hi @aiqbal,

    • Move dist(after angular build) items to *.Host/wwwroot
    • Then configure assets/appconfig.json
      "remoteServiceBaseUrl": "https://localhost:44301",
      "appBaseUrl": "https://localhost:44301",
    

    You can test with this.

    For your first question. We don't send headers from Angular, we send a normal request. Then middleware caches the request, takes the auth token from the request cookie, and adds it to the request header. That's the workflow of HTTP-only tokens.

  • User Avatar
    0
    aiqbal created

    Hi,

    We followed the steps with the AngularHttpOnlyCookieDemo project but it's not letting us login. We see in the console that there is an error relating to the AbpAutoValidateAntiforgeryTokenAuthorizationFilter.

    Would it be possible to get on a call where we could share our screen? I believe we could solve this rather quickly doing that.

  • User Avatar
    0
    aiqbal created

    We were able to get it working with a few tweaks. The missing part was that we needed to enable "withCredentials". Both in nswag and also in the XmlHttpRequestHelper.

    The above fixed the login issues but we also had to manually set abp.auth.isHttpOnlyCookieEnabled to true in abp.js for the rest of the site to work correctly once the user is logged in. Neither the blog post nor the demo project have this set to true so we aren't sure if this setting should be getting read from the c# side automatically. If it was supposed to be read automatically then it was not happening when we were trying it. Can you let us know if this should be getting updated based on the setting on the c# side.

  • User Avatar
    0
    m.aliozkaya created
    Support Team

    Hi @aiqbal,

    It needs to be enabled separately for both Angular and Host projects. It is looking as false on Angular in the blog post, we will update it. Has the problem been resolved by updating this?

  • User Avatar
    0
    aiqbal created

    Yes, we are ok now.