Swagger-ui: Request header field Authorization is not allowed by Access-Control-Allow-Headers

Created on 24 Oct 2014  路  6Comments  路  Source: swagger-api/swagger-ui

Hello,

My issue is related to the sending of the authorization header, which seems to be an issue which has been reported several times. However, none of the answers solved my issue, maybe because Swagger UI has evolved since.

Short description:

I have a Java REST API and a GET method which requires oauth2 authentication. Swagger got an access token from the API and the permission "On/Off button" is set to "On". I click on "Try it out!" to execute the request and get the following error in the console.

XMLHttpRequest cannot load http://localhost:8080/rest-oauth2/v1.0/events/1. Request header field Authorization is not allowed by Access-Control-Allow-Headers.

What is working?

I can successfully execute the following curl request from localhost:

$ curl -v -X GET -H "Content-Type: application/json" -H "Authorization: Bearer <access_token>" 'http://localhost:8080/rest-oauth2/v1.0/events/544777392dbf3cc5a3393bf7'

Swagger UI is available from an Apache server hosted on localhost. Methods documented correctly appear in Swagger UI. The above GET method is annotated with @ApiOperation (see below). Consequently, an On/Off button appears in Swagger UI for this method. When the user click on it, he is redirected to a login page I created. Its credentials are sent to the authentication provider which returns an access token. This token is sent to Swagger UI's page o2c.html, which in turns lead to the execution of the following instruction in swagger-oauth.js:

window.authorizations.add("oauth2", new ApiKeyAuthorization("Authorization", "Bearer " + b, "header"));

So far everything is fine and Swagger UI now has the access token required to get access to protected data. Now I click on "Try it out!" from a browser on locahost and get "Request header field Authorization is not allowed by Access-Control-Allow-Headers." in the browser console.

Output shown in Swagger UI:

Request URL: http://localhost:8080/rest-oauth2/v1.0/events/1
Response Body: no content
Response Code: 0
Response Headers: {}

The curl command works and the authentication header is accepted. Why not the authentication header from Swagger (is it effectively sent)?

Request Headers  (view source)
Accept:*/*
Accept-Encoding:gzip,deflate,sdch
Accept-Language:en-US,en;q=0.8
Access-Control-Request-Headers:accept, authorization, content-type
Access-Control-Request-Method:GET
Cache-Control:no-cache
Connection:keep-alive
DNT:1
Host:localhost:8080
Origin:http://localhost
Pragma:no-cache
Referer:http://localhost/swagger/
User-Agent:Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/38.0.2125.104 Safari/537.36
Response Headers (view source)
Access-Control-Allow-Headers:X-HTTP-Method-Override, Content-Type, x-requested-with
Access-Control-Allow-Methods:GET, POST, PUT, DELETE
Access-Control-Allow-Origin:http://localhost

More information about my setup (please feel free to request more if required):

Gradle.build file:
compile "com.wordnik:swagger-jersey2-jaxrs_2.11:1.3.10"

Annotation of the GET method (Java REST API):

    @ApiOperation(value = "Get event", response = ApiEvent.class,
        authorizations = { @Authorization(value = "oauth2",
            scopes = {
                @AuthorizationScope(scope = "read:events", description = "Read your events")
        })
    })

Swagger configuration:

        ConfigFactory.config().setApiVersion("1.0");
        ConfigFactory.config().setBasePath("http://localhost:8080/rest-oauth2");

        ApiInfo info = new ApiInfo(
                "REST Application",                             /* title */
                "HTML description",
                "http://helloreverb.com/terms/",                  /* TOS URL */
                "[email protected]",                            /* Contact */
                "Apache 2.0",                                     /* license */
                "http://www.apache.org/licenses/LICENSE-2.0.html" /* license URL */
        );

        List<AuthorizationScope> scopes = new ArrayList<AuthorizationScope>();
        scopes.add(new AuthorizationScope("read:events", "Read your events (config)"));

        List<GrantType> grantTypes = new ArrayList<GrantType>();

        ImplicitGrant implicitGrant = new ImplicitGrant(
                new LoginEndpoint("http://localhost:8080/rest-oauth2/swagger_login.html"),
                "access_token");

        grantTypes.add(implicitGrant);

        AuthorizationType oauth = new OAuthBuilder().scopes(scopes).grantTypes(grantTypes).build();

        ConfigFactory.config().addAuthorization(oauth);
        ConfigFactory.config().setApiInfo(info);

Swagger UI index.html:

            initOAuth({
              clientId: "353b302c44574f565045687e534e7d6a", // test clients
              realm: "test", // defined in spring/oauth/oauth2-configuration.xml
              appName: "your-app-name"
            });

Thank you for your help

Most helpful comment

Hi, this is because your server isn't allowing the authorization header. In your output of the response headers above, you have this:

Access-Control-Allow-Headers:X-HTTP-Method-Override, Content-Type, x-requested-with

That means, you can send headers cross-domain with only the above names. Note, no authorization in there.

To address it, consider adding a CORS filter like the sample here:

https://github.com/swagger-api/swagger-core/blob/master/samples/java-grails2/src/java/com/wordnik/swagger/sample/util/ApiOriginFilter.java

and set the header:

res.addHeader("Access-Control-Allow-Headers", "Content-Type, authorization");

All 6 comments

Hi, this is because your server isn't allowing the authorization header. In your output of the response headers above, you have this:

Access-Control-Allow-Headers:X-HTTP-Method-Override, Content-Type, x-requested-with

That means, you can send headers cross-domain with only the above names. Note, no authorization in there.

To address it, consider adding a CORS filter like the sample here:

https://github.com/swagger-api/swagger-core/blob/master/samples/java-grails2/src/java/com/wordnik/swagger/sample/util/ApiOriginFilter.java

and set the header:

res.addHeader("Access-Control-Allow-Headers", "Content-Type, authorization");

That solved my issue. Thanks for your answer and your outstanding work on Swagger UI.

Hi,

Just to clarify, I do not have a problem using Swager UI, my question is about inconsistency between cURL and Swager UI - cURL seems to somehow overcome/disregard the problem and not fail.

Do you have an insight why this worked with cURL before making the change on server? I would have expected the cURL to fail in the same fashion as Swagger UI.

Thanks a lot.
Irena

CORS is A browser requirement which is why Swagger UI needs it to work. Curl doesn't carry the same constraints so it works without it.

Webron, thank you for the explanation, this is clear now :).

@fehguy Please, could you post the code? The repo that you had citted has been changed.

I'm having the same problem with my SpringBoot server app. I've added the "authorization" header in my CorsFilter.java but the problem continues.

Was this page helpful?
0 / 5 - 0 ratings