7

Can anyone tell me why my 'WWW-Authenticate' header is null in the response, eventhough I am able see the stringified 'WWW-Authenticate' header object in the Chrome dev tools?

On the server side I am doing the following to set my WWW-Authenticate header as well as set the proper headers for CORS:

res.setHeader('Access-Control-Allow-Origin', 'http://localhost:8080');
res.setHeader('Access-Control-Expose-Headers', 'WWW-Authenticate');
res.setHeader('WWW-Authenticate', JSON.stringify({
    "token": "encryptedToken", 
    "message": "encryptedMessage"
}));

I believe that I am setting the header correctly on the server side, because When I look at the Chrome Dev tools, I see the following under "Response Headers" for the request that is being made.

Response Headers
Access-Control-Allow-Origin:http://localhost:8080
Access-Control-Expose-Headers:WWW-Authenticate
Connection:keep-alive
Date:Fri, 15 May 2015 13:48:29 GMT
ETag:W/"f7-1470611871"
WWW-Authenticate: {"token":"encryptedToken","message":"encryptedMessage"}
X-Powered-By:Express

HOWEVER, when I try to access the "WWW-Authenticate" header from within the response, I get NULL.

$http.get("http://localhost:4242/days")
.then(function (response) {
    var AuthHeader = response.headers('WWW-Authenticate');
    console.log (AuthHeader); // returns null
})

Thank you for your help in advance!

Riley P
  • 73
  • 1
  • 6
  • try logging the whole response object – charlietfl May 15 '15 at 15:54
  • response object --- {data: Array[7], status: 200, headers: function, config: Object, statusText: "OK"} – Riley P May 15 '15 at 16:07
  • no, I want to to access the 'WWW-Authenticate' header object(still stringified), but the response.headers function keeps returning null even though I can see the object in the dev tools. – Riley P May 15 '15 at 16:10
  • Out of curiosity what happens if you console.log(response.headers())? – ChrisSwires May 15 '15 at 16:12
  • Object {content-type: "application/json; charset=utf-8"}. – Riley P May 15 '15 at 16:16
  • Hmmm.... So you can't access it because it isn't there... As to the why. Unsure. Will see if I can find anything. – ChrisSwires May 15 '15 at 16:17
  • @RileyP Just musing here but could the issue be the encoding used on the json within the custom header? Maybe angular is unable to parse it given that it'll be expecting a string? Could test by returning a string from your back-end to rule it out? – ChrisSwires May 15 '15 at 16:32
  • I did as you said and set the header to a string. The header is still not there. – Riley P May 15 '15 at 16:43
  • @RileyP Also. Shot in the dark here but perhaps Angular is expecting it. It's common (though I beleive now deprecated practice) to pre-pend custom headers with X- – ChrisSwires May 15 '15 at 16:44
  • That was it!! X-WWW-Authenticate is the answer! Please post your help as an answer so I can give you credit. Thanks Swires – Riley P May 15 '15 at 16:55
  • Done and happy to help. It was bugging me too :) – ChrisSwires May 15 '15 at 17:07

3 Answers3

2

The Access-Control-Expose-Headers header can be set to include www-authenticate. This header will allow clients, including Angular, to read those response headers on a CORS request.

If you're using ASP.NET Web API, then you set the exposedHeaders either directly on the System.Web.Cors.CorsPolicy.ExposedHeaders parameter or you can add an attribute to the controller method. The attribute method is described at Enabling Cross-Origin Requests in ASP.NET Web API 2.

Here are a couple examples using ASP.NET Web API.

Example: Setting the ExposedHeaders parameter

var corsPolicy = new CorsPolicy();
corsPolicy.ExposedHeaders.Add("www-authenticate");

var corsOptions = new CorsOptions
{
    PolicyProvider = new CorsPolicyProvider
    {
        PolicyResolver = context => Task.FromResult(corsPolicy)
    }
};

app.UseCors(corsOptions);

Example: Using an attribute

[EnableCors(origins: "*", headers: "*", methods: "*", exposedHeaders: "www-authenticate")]
public class TestController : ApiController
{
    // ...
}

If you're using a different framework for your API, then you'll need to research that framework to see how to set the Access-Control-Expose-Headers header.

Toby Artisan
  • 1,639
  • 3
  • 23
  • 26
2

It's not client issue, in CORS situation the browser won't allow this header because it doesn't receive a green light (another header) from the server indicating that it can be exposed to the client !

So for those who are using ASP.NET Core you can expose this header as so in Startup.cs :

void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    ...
    app.UseCors(x => x.AllowAnyOrigin()
    .AllowAnyMethod()
    .AllowAnyHeader()
    .WithExposedHeaders("WWW-Authenticate"));

Or

void ConfigureServices(IServiceCollection services)
    ...
    services.AddCors(options =>
    {
        var corsPolicy = new CorsPolicy();
        corsPolicy.Origins.Add("*");
        corsPolicy.Methods.Add("*");
        corsPolicy.Headers.Add("*");
        corsPolicy.ExposedHeaders.Add("WWW-Authenticate");
        options.AddPolicy("CorsPolicy", corsPolicy);
    });

void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    ...
    app.UseCors("CorsPolicy")
abdelgrib
  • 843
  • 7
  • 11
1

Ok... So after a bit of trial and error we've figured this out. I had though that pre-pending X- to custom headers was an outdated and unneccessary paractive, however it appears that either the browser being used in this case or perhaps angular itself is expecting it.

Changing the header name from:

WWW-authenticate

to

X-WWW-authenticate

Resolves the issue. If anyone can shed any light on this please do.

In fact, referencing the first answere here: Custom HTTP headers : naming conventions the use of X- has been deprecated and in fact the headers should just be 'sensibly named' sans any prefix. Perhaps consider renaming to:

appName-authenticate

Or similar as a best practice.

Community
  • 1
  • 1
ChrisSwires
  • 2,713
  • 1
  • 15
  • 28