Axios get access to response header fields
Asked Answered
P

17

332

I'm building a frontend app with React and Redux and I'm using axios to perform my requests. I would like to get access to all the fields in the header of the response. In my browser I can inspect the header and I can see that all the fields that I need are present(such as token, uid, etc...), but when I call

const request = axios.post(`${ROOT_URL}/auth/sign_in`, props);
request.then((response)=>{
  console.log(response.headers);
});

I get just

Object {content-type: "application/json; charset=utf-8", cache-control: "max-age=0, private, must-revalidate"}

Here my browser network tab,as you can see all the other fields are present.

enter image description here

Bests.

Penal answered 18/6, 2016 at 13:29 Comment(3)
If you print out axios.defaults.headers does that give you any of the one's you're missing? Some headers are configured at that level, not at that of each request (see github.com/mzabriskie/axios#global-axios-defaults)Urumchi
Is not it axios.defaults.headers for configure the REQUEST header params? I need to access the RESPONSE one. @BenHarePenal
BTW, what you called request, is not a request. It's a promise for your response. Your request was what you passed to the post() method as arguments.Compel
E
558

In case of CORS requests, browsers can only access the following response headers by default:

  • Cache-Control
  • Content-Language
  • Content-Type
  • Expires
  • Last-Modified
  • Pragma

If you would like your client app to be able to access other headers, you need to set the Access-Control-Expose-Headers header on the server:

Access-Control-Expose-Headers: Access-Token, Uid
Eras answered 20/6, 2016 at 20:15 Comment(8)
My bad I forgot to expose that fields.Penal
If you are using Rails with Rack-Cors you need to set expose: ['Access-Token', 'Uid'] on the origin like: resource '*', :headers => :any, :methods => [:get, :post, :put, :patch, :delete, :options, :head], expose: ['Access-Token', 'Uid']Split
I don't get it. If they are not exposed, why are the additional headers visible in the browser but not in the axios response?Bulley
@adanilev, browsers allow you to see them for debugging purposes, but prevent you from accessing them through APIs for security reasons. It prevents clients from getting secured credentials from servers, allowing the server to determine what access a client has. TLDR: it's done on purpose for securityKee
I have this in my NGINX confg file... 'Access-Control-Expose-Headers' 'Authorization, X-Suggested-Filename, content-disposition' always; Still only see content-type: "application/pdf" really need to pull content-dispositionEba
In my grails server app i have set expose headers as cors.expose.headers = ['authorization'] and i am seeing the Access-Control-Expose-Headers : Authorization in my network tab as well. But i am not able to get it from axios response. Here also in @Penal question, network tab already contains Access-Control-Expose-Headers : Authorization but why wasn't he able to access the headers? Please help.Horrendous
I solved it by adding header("Access-Control-Allow-Headers: Authorization, Custom-Header") in PHP back-end.Longhand
Thanks. Worked in Java Spring response.addHeader("Access-Control-Expose-Headers", "Access-Token"); response.addHeader("Access-Token","yourToken"); where response is the HttpServletResponseCockroach
K
47

This really helped me, thanks Nick Uraltsev for your answer.

For those of you using nodejs with cors:

...
const cors = require('cors');

const corsOptions = {
  exposedHeaders: 'Authorization',
};

app.use(cors(corsOptions));
...

In the case you are sending the response in the way of res.header('Authorization', `Bearer ${token}`).send();

Kneel answered 1/7, 2018 at 20:41 Comment(1)
For those wondering, you could pass an array here too: exposedHeaders: ['Authorization','X-Total-Count']Backfill
T
20

I was facing the same problem. I did this in my WebSecurity.java, it's about the setExposedHeaders method in the CORS configuration.

@Bean
CorsConfigurationSource corsConfigurationSource() {

    CorsConfiguration configuration = new CorsConfiguration();
    configuration.setAllowCredentials(true);
    configuration.setAllowedOrigins(Arrays.asList(FRONT_END_SERVER));
    configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE"));
    configuration.setAllowedHeaders(Arrays.asList("X-Requested-With","Origin","Content-Type","Accept","Authorization"));
    
    // This allow us to expose the headers
    configuration.setExposedHeaders(Arrays.asList("Access-Control-Allow-Headers", "Authorization, x-xsrf-token, Access-Control-Allow-Headers, Origin, Accept, X-Requested-With, " +
            "Content-Type, Access-Control-Request-Method, Access-Control-Request-Headers"));
    
    UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    source.registerCorsConfiguration("/**", configuration);
    return source;
}

I hope it works.

Teratism answered 22/10, 2018 at 1:40 Comment(0)
D
19

Faced same problem in asp.net core Hope this helps

public static class CorsConfig
{
    public static void AddCorsConfig(this IServiceCollection services)
    {
        services.AddCors(options =>
        {
            options.AddPolicy("CorsPolicy",
                builder => builder
                .WithExposedHeaders("X-Pagination")
                );
        });
    }
}
Debauchee answered 16/4, 2019 at 18:41 Comment(1)
Welcome to SO! Your answer may be correct but at StackOverflow, it is discouraged to post code only answer. Please try to provide an explanation of how your answer solves the original question. please read this on how to Write Better AnswerGarold
G
9

In axios CORS requests, browsers can access only few headers by default.

But if you need to access a custom header from response, you have to send response with Access-Control-Expose-Headers form your backend server.

Hare is a example for Nodejs backend and Reactjs front end:

res.header('Access-Control-Expose-Headers', 'x-xsrf-token');

return res.header("x-xsrf-token", token).status(200)
           .send({
                id: user.id,
                email: user.email,
            });

res.header('Access-Control-Expose-Headers', 'x-xsrf-token');

for this line I can log my custom header like

axios.post("/login", {
            email: emailInput.current.value,
            password: passwordInput.current.value,
        })
        .then(function (response) {

            console.log(response.headers["x-xsrf-token"]);

        });

Without Access-Control-Expose-Headers in your response you will get undefine in console log. Check your response header in network tab that it contains the header with your custom name with it.

Gush answered 17/12, 2022 at 6:7 Comment(0)
P
7

According to official docs:

This may help if you want the HTTP headers that the server responded with. All header names are lower cased and can be accessed using the bracket notation. Example: response.headers['content-type'] will give something like: headers: {},

Plage answered 9/4, 2020 at 6:38 Comment(0)
C
7

Custom HTTP headers can not be accessed on client-side due to CORS restrictions. You need to add Access-Control-Expose-Headers setting on the server-side.

What are Access-Control-Expose-Headers?
Please go to https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Expose-Headers

By default only these HTTP headers are exposed:

  • Cache-Control
  • Content-Language
  • Content-Length
  • Content-Type
  • Expires
  • Last-Modified
  • Pragma

For custom HTTP headers, you need to customize Access-Control-Expose-Headers in response headers.

If you are using Django on the server side you can use django-cors-headers (https://pypi.org/project/django-cors-headers/) for CORS settings management.

For example, with django-cors-headers you can add a list of HTTP headers that are to be exposed to the browser by CORS_ALLOW_HEADERS setting

from corsheaders.defaults import default_headers

CORS_ALLOW_HEADERS = list(default_headers) + [
    'my-custom-header',
]

Cowbind answered 9/10, 2020 at 9:54 Comment(0)
D
7

There is one more hint that not in this conversation. for asp.net core 3.1 first add the key that you need to put it in the header, something like this:

Response.Headers.Add("your-key-to-use-it-axios", "your-value");

where you define the cors policy (normaly is in Startup.cs) you should add this key to WithExposedHeaders like this.

          services.AddCors(options =>
        {
        options.AddPolicy("CorsPolicy",
            builder => builder
                .AllowAnyHeader()
                .AllowAnyMethod()
                .AllowAnyOrigin()
                .WithExposedHeaders("your-key-to-use-it-axios"));
        });
    }

you can add all the keys here. now in your client side you can easily access to the your-key-to-use-it-axios by using the response result.

          localStorage.setItem("your-key", response.headers["your-key-to-use-it-axios"]);

you can after use it in all the client side by accessing to it like this:

const jwt = localStorage.getItem("your-key")
Diu answered 6/1, 2021 at 17:43 Comment(0)
A
3

In case you're using Laravel 8 for the back-end side with CORS properly configured, add this line to config/cors.php:

'exposed_headers' => ['Authorization'],

Attribute answered 23/10, 2020 at 19:44 Comment(1)
Thank you for that. I tried the wildcard '*' , which did'nt work, but using your answer as help it really helped me.Jequirity
C
2

for django help

CORS_EXPOSE_HEADERS = [
        'your header'
    ]
Colored answered 31/3, 2020 at 17:22 Comment(1)
At least for Flask CORS, you can also pass a dict where each key is named CORS_<property> (in this case expose_headers) and pass it with the desired values in the CORS(app, **cors_config) statement. See docs hereMiasma
S
2

For the SpringBoot2 just add

httpResponse.setHeader("Access-Control-Expose-Headers", "custom-header1, custom-header2");

to your CORS filter implementation code to have whitelisted custom-header1 and custom-header2 etc

Schoolmistress answered 4/5, 2020 at 21:10 Comment(0)
I
2

try like this

            .then(res =>{
                console.log(res);
                console.log(res.headers['x-total-count']);
                setTotalRecords(res.headers['x-total-count']);
                setTableData(res.data);
            });
Indemnity answered 23/9, 2021 at 4:38 Comment(0)
T
2

Below the list of clear steps to make sure you don't need to spend the whole evening googling as I did. I address the matter of how to read the Authorization header in the axios response (!).

For the back-end I am using standard ExpressJS. I am using: cors() and helmet() middleware in Express with the empty configuration but the below works nonetheless.

  1. Make sure your backend sends Access-Control-Expose-Headers. At the begining set it to * to eliminate other possibilities. In Express, this going to be:
res.setHeader('Access-Control-Expose-Headers', '*')
  1. Make sure your backend sends Access-Control-Allow-Headers. Don't confuse with the 1st. step as both sound similar. Set this to cover all the headers you want to read from. In my case:
res.setHeader('Access-Control-Allow-Headers', 'Authorization,x-client-session')
  1. In your front-end app, Axios will return "AxiosHeaders" type for the headers. You should have your headers exposed now. Specifically for Authorization use:
const res = await axios(init)
const authHeader = res.headers.getAuthorization()

Even in the most up to date package version you may get TypeScript error that: This expression is not callable but it is.

This is it.

Tanjatanjore answered 6/6, 2023 at 21:31 Comment(0)
A
1

For Spring Boot 2 if you don't want to use global CORS configuration, you can do it by method or class/controller level using @CrossOrigin adnotation with exposedHeaders atribute.

For example, to add header authorization for YourController methods:

@CrossOrigin(exposedHeaders = "authorization")
@RestController
public class YourController {
    ...
}
Assurbanipal answered 20/7, 2020 at 20:46 Comment(0)
U
1

[expanding on what @vladimir said]

if you're using Django
and django-cors-headers to allow/control CORS, you should set the following, in your settings.py

CORS_EXPOSE_HEADERS = ['yourCustomHeader']
Unkind answered 21/7, 2021 at 18:33 Comment(0)
K
1

If you are using Django without django-cors-headers, you can write custom middleware.

class CustomCorsMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        response['Access-Control-Expose-Headers'] = 'MY-HEADER, ANOTHER-HEADER'

        return response

You can also set other CORS heades here.

Then you should register your middleware by inserting it at the beggining of the MIDDLEWARE list in your project's settings.py file.

MIDDLEWARE = [
    'myapp.middleware.CustomCorsMiddleware',
    ...
]
Kayekayla answered 22/2, 2022 at 16:58 Comment(0)
I
0

If you are working with Spring Boot 3 and Spring Security 6 or up, this could work:

In your @Configuration class includes this:


    @Bean
    public CorsFilter corsFilter() {
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        CorsConfiguration config = new CorsConfiguration();
    
        config.addAllowedOrigin("*");
        config.addAllowedMethod("*");
    
        //Allow several headers
        config.addAllowedHeader("Authorization");
        config.addAllowedHeader("X-Custom-Header");
        config.addAllowedHeader("Another-Header");
    
        // Expose custom headers
        config.addExposedHeader("Authorization");
        config.addExposedHeader("X-Custom-Header");
        config.addExposedHeader("Another-Header");
    
        source.registerCorsConfiguration("/**", config);
        return new CorsFilter(source);
    }

Be careful cause the previous configuration is so general.

Izak answered 11/9, 2023 at 4:7 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.