Swagger-UI: Headers not getting set, Uncaught type error

2,868 views
Skip to first unread message

Jeff Crump

unread,
May 22, 2015, 5:44:07 PM5/22/15
to swagger-sw...@googlegroups.com
Hi,

I am trying to connect Swagger-UI (code from today) with my Swagger-enabled service.  I need to send over an Authorization header for CORS purposes, and I'm trying to do this as prescribed in the doc:

$('#input_apiKey').change(function() {
  var key = $('#input_apiKey')[0].value;
  if(key && key.trim() != "") {
    swaggerUi.api.clientAuthorizations.add("Authorization", new SwaggerClient.ApiKeyAuthorization("Authorization", key, "header"));
  }
})

The request to get the Swagger JSON is failing because the header is not set.  The service has CORS enabled -- it has been working fine against a version of Swagger-UI from March, 2015 -- so it's most likely not a problem on my service side.  

When I look at the request, the Authorization header is not there.

Thinking perhaps I could make it work at page-load time,  I did this in index.html:

    var apiKey = "<header value>";
    $('#input_apiKey').val(apiKey);
    addApiKeyAuthorization();  // call addApiKey
    window.swaggerUi.load();

But the call to addApiKeyAuthorization fails on this line:
    swaggerUi.api.clientAuthorizations.add("Authorization", new SwaggerClient.ApiKeyAuthorization("Authorization", key, "header"));

with the error:

            Uncaught TypeError: Cannot read property 'clientAuthorizations' of null 


Please help. I really want to make this work. Thanks.

Josh Ponelat

unread,
May 23, 2015, 12:01:03 AM5/23/15
to swagger-sw...@googlegroups.com
Hi Jeff,

Thanks for showing the snippet,
addApiKeyAuthorization needs to be called in `onComplete`. This was a bug, but has been fixed( ie we removed the line).
Try updating to the latest version (recommended). Or otherwise take a look at the working index.html file....
https://github.com/swagger-api/swagger-ui/blob/master/dist/index.html#L36-L75

Jeff Crump

unread,
May 23, 2015, 9:42:07 AM5/23/15
to swagger-sw...@googlegroups.com
Thanks, but that doesn't work (I already had the most recent code). Here is my onComplete method: 

 onComplete: function(swaggerApi, swaggerUi){
          if(typeof initOAuth == "function") {
            initOAuth({
              clientId: "your-client-id",
              realm: "your-realms",
              appName: "your-app-name"
            });
          }

          $('pre code').each(function(i, e) {
            hljs.highlightBlock(e)
          });

          addApiKeyAuthorization();
        },

I set a breakpoint at the start of this method and it's never getting called.  It seems that the call to get the initial JSON needs the header and since it doesn't have it, the call fails.  Thus onComplete is never called; in fact, the onFailure method is called.


--
You received this message because you are subscribed to a topic in the Google Groups "Swagger" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/swagger-swaggersocket/tJ0YHdTnBRk/unsubscribe.
To unsubscribe from this group and all its topics, send an email to swagger-swaggers...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Josh Ponelat

unread,
May 24, 2015, 1:46:19 AM5/24/15
to swagger-sw...@googlegroups.com
Ok,
I believe swagger-js (and swagger-ui) need to be able to get a successful(200) OPTIONS request /before/ it can send out the headers. If you  have that, then it should work.
Here is the comment that addresses that... https://github.com/swagger-api/swagger-ui/issues/1171#issuecomment-100374999

Jeff Crump

unread,
May 25, 2015, 6:25:25 PM5/25/15
to swagger-sw...@googlegroups.com
My network log doesn't show any OPTIONS requests from my browser.   My service, however, is getting a GET request but it's returning 500 because the Authorization header was not present.

So, how do I get this header set into the initial request for the swagger JSON?

Josh Ponelat

unread,
May 26, 2015, 2:52:04 AM5/26/15
to swagger-sw...@googlegroups.com
This could be an issue with the server, you would need to enable preflight requests - which is what the OPTIONS request falls under.
However you mentioned that you have this working on a previous version of Swagger-UI?

Try to see if curl works... here is a nice SO question/answer relating to debugging CORS (and preflight requests)

I believe its a requirement for CORS, that a successful preflight occurs (which does not include your headers).

Thanks for holding on though, debugging requests can be tricky!


--
You received this message because you are subscribed to the Google Groups "Swagger" group.
To unsubscribe from this group and stop receiving emails from it, send an email to swagger-swaggers...@googlegroups.com.

Jeff Crump

unread,
May 26, 2015, 8:36:48 AM5/26/15
to swagger-sw...@googlegroups.com
Yes, I can connect and fetch the JSON with a GET request, as long I supply the required "Authorization" header. This header isn't being sent on the initial request by Swagger. 

I also tried turning off Chrome's browser security. As expected, this failed if I did not supply the header.  So the server is fine.

tony tam

unread,
May 26, 2015, 10:02:31 AM5/26/15
to swagger-sw...@googlegroups.com, jeffre...@gmail.com
Is the server on the same host/port/protocol as the swagger-ui?  If so, there will be no CORS preflight request (OPTIONS).

You'll have to share more of your swagger JSON.  The most common misconfiguration is that you have empty `security` definitions on operations, which tells swagger that no headers/security mechanisms are required.
To unsubscribe from this group and all its topics, send an email to swagger-swaggersocket+unsub...@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.

--
You received this message because you are subscribed to the Google Groups "Swagger" group.
To unsubscribe from this group and stop receiving emails from it, send an email to swagger-swaggersocket+unsub...@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.

--
You received this message because you are subscribed to a topic in the Google Groups "Swagger" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/swagger-swaggersocket/tJ0YHdTnBRk/unsubscribe.
To unsubscribe from this group and all its topics, send an email to swagger-swaggersocket+unsub...@googlegroups.com.

Jeff Crump

unread,
May 26, 2015, 10:46:45 AM5/26/15
to swagger-sw...@googlegroups.com
No. My swagger-ui is hosted in our GitHub pages.  The server side has not changed since March, and this whole thing fell apart when I took the latest code for Swagger-UI. I'm this close to giving up...

To unsubscribe from this group and all its topics, send an email to swagger-swaggers...@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.

--
You received this message because you are subscribed to the Google Groups "Swagger" group.
To unsubscribe from this group and stop receiving emails from it, send an email to swagger-swaggers...@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.

--
You received this message because you are subscribed to a topic in the Google Groups "Swagger" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/swagger-swaggersocket/tJ0YHdTnBRk/unsubscribe.
To unsubscribe from this group and all its topics, send an email to swagger-swaggers...@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.

--
You received this message because you are subscribed to a topic in the Google Groups "Swagger" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/swagger-swaggersocket/tJ0YHdTnBRk/unsubscribe.
To unsubscribe from this group and all its topics, send an email to swagger-swaggers...@googlegroups.com.

Jeff Crump

unread,
May 26, 2015, 11:05:11 AM5/26/15
to swagger-sw...@googlegroups.com
When I load index.html, I am getting called on my URL but the call is expecting the Authorization header, and returns an error.  Where does that header get inserted for this initial call?

Jeff Crump

unread,
May 26, 2015, 1:55:18 PM5/26/15
to swagger-sw...@googlegroups.com
OK, I've managed to figure out what's going on, once I improved my Javascript debugging experience. 

Swagger UI cannot get the JSON from my service because of a problem in the relationship between SwaggerClient and SwaggerUi.   First, window.swaggerUi.load() calls 'new SwaggerClient(this.options)'.   This ultimately calls SwaggerClient.prototype.initialize which does this:

if (options.authorizations) {
    this.clientAuthorizations = options.authorizations;
  } else {
    this.clientAuthorizations = new auth.SwaggerAuthorizations();
  }

But we've not yet been called back to set the authorizations, so they're not set.  And we can't just call  window.swaggerUi.api.clientAuthorizations.add from index.html because the initialization of swaggerUi has not yet happened (window.swaggerUi.api is not yet initialized).

To prove this out, I inserted this hack into swagger-ui.js just after that if statement:

var apiKeyAuth = new SwaggerClient.ApiKeyAuthorization("Authorization", "Basic Uk9WSU5HOlJPVklORw==", "header");
  this.clientAuthorizations.add("Authorization", apiKeyAuth);

Voila, the request processed correctly.

Next, I tried to invoke one of my methods.  The addApiKeyAuthorization function was being correctly called. For a header, however, the URI encoding is not appropriate so the value was being corrupted.  I fixed it like so:

function addApiKeyAuthorization(){
        // Don't encode, it corrupts the header: var key = encodeURIComponent($('#input_apiKey')[0].value);
        var key = $('#input_apiKey')[0].value;
        if(key && key.trim() != "") {
            var apiKeyAuth = new SwaggerClient.ApiKeyAuthorization("Authorization", key, "header");
            window.swaggerUi.api.clientAuthorizations.add("Authorization", apiKeyAuth);
            log("added key " + key);
        }
      }

Now everything is working fine.

So, in short, the initialization sequence is broken because of the lack of an opportunity to set the authorization header. Perhaps you need to add another callback after the SwaggerAuthorizations array has been created but before SwaggerUi constructor returns.

Or maybe there is a hook that I'm unaware of?

One could say that the encoding of the header is also a bug, but since it's in the index.html one could also say it's a client-side issue.

Let me know if there's anything else I can find out for you (or if I can submit a defect).  Naturally I won't be taking any new drops of the software until this is fixed. 

Thanks,

Jeff

Jeff Crump

unread,
Jun 2, 2015, 8:58:24 AM6/2/15
to swagger-sw...@googlegroups.com
Anyone care to comment on this?  Seems pretty broken to me.  Thanks.

Josh Ponelat

unread,
Jun 2, 2015, 9:08:55 AM6/2/15
to swagger-sw...@googlegroups.com
Hi Jeff,

Yes, thank you for digging so deep.
Let me see if I can't use the authorizations field to set headers on the initial fetching of the spec.
As you can send in swagger-js options from swagger-ui. But this would mean knowing something about SwaggerAuthorizations

I'll quickly check now....


Josh Ponelat

unread,
Jun 2, 2015, 9:29:30 AM6/2/15
to swagger-sw...@googlegroups.com
Short of recreating a rough implementation of SwaggerAuthorization (yuck), there isn't much one can do.
This is a bug in my opinion.

Authorizations only get applied after we fetch the spec file. Why should we assume that spec files are public?

I think the correct functionality should be so....
the authorization field/option in creating SwaggerUi/SwaggerJS can contain a hash of authName->authFunc, which will get appended to a fresh SwaggerAuthorization instance.
This happens before any HTTP executes are done. The only question is whether we should have a special authName for fetching the spec file (so that spec specific headers/tokens don't get sent with other requests).

Jeff, you're welcome to make an issue in swagger-js. If you don't I will (soonish).

Jeff Crump

unread,
Jun 2, 2015, 9:33:35 AM6/2/15
to swagger-sw...@googlegroups.com
Thanks for looking into this, Josh.  Please go ahead and create the issue -- you're much more knowledgeable on what's going on than I am.  Thanks.

Jeff

Josh Ponelat

unread,
Jun 2, 2015, 9:50:24 AM6/2/15
to swagger-sw...@googlegroups.com
Sure thing...
Here is the issue you can follow (if your heart so desires it)
https://github.com/swagger-api/swagger-js/issues/445

Amanda Lee

unread,
Jun 26, 2015, 5:03:52 PM6/26/15
to swagger-sw...@googlegroups.com
Hi, recently I'm encountering similar problem. I want to add authorization to the header via swagger ui. I want to add username and password to the header. When I use Postman, I can add it at "Basic Auth", it will generate a custom header. For swagger, I changed the addApiKeyAuthorization to the following in index.html page. I can see this method is called, and can see the log. But still when I send request via swagger, the authorization header is not there. Could you give me some hint on this one? Thanks.

function addApiKeyAuthorization(){
    
          var value = "auth-scheme username=a,password=a";
          var authKeyHeader = new window.SwaggerClient.ApiKeyAuthorization("Authorization", value, "header");
          window.swaggerUi.api.clientAuthorizations.add("Authorization", authKeyHeader);
          log("added username  password ");
To unsubscribe from this group and all its topics, send an email to swagger-swaggersocket+unsub...@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.

--
You received this message because you are subscribed to the Google Groups "Swagger" group.
To unsubscribe from this group and stop receiving emails from it, send an email to swagger-swaggersocket+unsub...@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.

--
You received this message because you are subscribed to a topic in the Google Groups "Swagger" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/swagger-swaggersocket/tJ0YHdTnBRk/unsubscribe.
To unsubscribe from this group and all its topics, send an email to swagger-swaggersocket+unsub...@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.

--
You received this message because you are subscribed to a topic in the Google Groups "Swagger" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/swagger-swaggersocket/tJ0YHdTnBRk/unsubscribe.
To unsubscribe from this group and all its topics, send an email to swagger-swaggersocket+unsub...@googlegroups.com.

Josh Ponelat

unread,
Jun 27, 2015, 12:01:07 AM6/27/15
to swagger-sw...@googlegroups.com
Hi Amanda,

There is a special method for Basic HTTP Authorization (username + password + base64)...

Try this...

var authKeyHeader = new window.swaggerUi.api.PasswordAuthorization("", "<username>", "<password>");
window.swaggerUi.api.clientAuthorizations.add("basicAuthOrAnotherName", authKeyHeader);
log("added basic auth (username/password)");

PS:
Note I'm using swaggerUi.api instead of SwaggerClient... the latter which has become deprecated.

Also, let me know if I mis-understood.

To unsubscribe from this group and all its topics, send an email to swagger-swaggers...@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.

--
You received this message because you are subscribed to the Google Groups "Swagger" group.
To unsubscribe from this group and stop receiving emails from it, send an email to swagger-swaggers...@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.

--
You received this message because you are subscribed to a topic in the Google Groups "Swagger" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/swagger-swaggersocket/tJ0YHdTnBRk/unsubscribe.
To unsubscribe from this group and all its topics, send an email to swagger-swaggers...@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.

--
You received this message because you are subscribed to a topic in the Google Groups "Swagger" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/swagger-swaggersocket/tJ0YHdTnBRk/unsubscribe.
To unsubscribe from this group and all its topics, send an email to swagger-swaggers...@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.

--
You received this message because you are subscribed to the Google Groups "Swagger" group.
To unsubscribe from this group and stop receiving emails from it, send an email to swagger-swaggers...@googlegroups.com.

Amanda Lee

unread,
Jun 29, 2015, 11:55:13 AM6/29/15
to swagger-sw...@googlegroups.com
Hi Josh.
  
thank you for your time. I tired your method, I added the following code, but the first line shows error: "Uncaught TypeError: undefined is not a function". How should solve this one? Thanks.

         var authKeyHeader = new window.swaggerUi.api.PasswordAuthorization("", "admin", "admin");
        window.swaggerUi.api.clientAuthorizations.add("Authorization", authKeyHeader);
        log("added basic auth (username/password)");
Here is the watch list when I debug it.
Inline image 1

Josh Ponelat

unread,
Jun 29, 2015, 1:44:46 PM6/29/15
to swagger-sw...@googlegroups.com
Hmm try the old way...
var authBasicAuth  = new SwaggerClient.PasswordAuthorization('', 'admin', 'admin');

Amanda Lee

unread,
Jun 29, 2015, 2:05:10 PM6/29/15
to swagger-sw...@googlegroups.com
Hi, Josh, the old way is working. Thanks~

Do you know how to prompt a login window to let user enter the username and password? i tried the javascript prompt, but it only contains one field. I would like to see two fields in a form to login. As I google it, it seems like I need to create another login page, if login succeed, then direct to success page. I wonder if you know some other way instead of creating a login page. Thanks.

Josh Ponelat

unread,
Jul 1, 2015, 2:09:11 AM7/1/15
to swagger-sw...@googlegroups.com
Well, it's a little out of context of swagger ;)

Most of the time I just use HTTP Basic authentication, which is from the server side. It's the only pop-up prompt I know of. If you don't add the above authentication, the server will prompt you for the user/pass itself... unfortunately it /might/ do this each time you try and access a different resource...

The rest relies on what javascript infrastructure you have and your server.

Simply having a prompt, won't stop anyone who wants to get in. Unless you validate it with the server.
Still, you could always have two prompts .. if you like ;) not that I recommend it from a security point of view.

PS:
It is very unsafe to store real user/data inside the javascript memory space and/or the DOM, and should NOT be used in production.

Reply all
Reply to author
Forward
0 new messages