How to make Swagger sign a request body and put the calculated hash in the request headers

3,429 views
Skip to first unread message

j3d

unread,
Jul 31, 2014, 1:46:08 AM7/31/14
to swagger-sw...@googlegroups.com
Hello,

Till now I've used a GUID as the API key and just compared the api_key header with the key provided via Swagger-ui... but now it is time to get serious so I'm implementing a private/public key mechanism where I'll provide two headers: one containing the public api_key (as before) and another one containging the HMAC signature generated by hashing the request body.

When the backend receives the requests, it uses the public API key (api_key header) to retrieve the secret key from the database and then hashes the body of the incoming request. If the resulting hash matches with the signature contained in the request headers, then the request is accepted, otherwise it is rejected.

The question is: how do I make Swagger sign the request body and put the calculated hash in the request headers?

Thanks,
j3d

Ron

unread,
Jul 31, 2014, 7:19:25 AM7/31/14
to swagger-sw...@googlegroups.com
Basically, what you want is to add another header parameter. This can be done either as a header parameter per operation or as an authorization scheme with a header-typed api key.

As for 'make Swagger sign the request body' - that's not something Swagger does.
I assume that when you say Swagger here, you mean the UI, and just like any other client that you'd have to tell it to do so, so you would need to tell Swagger-UI to do it with changes to its code. This is definitely doable.


--
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.

Tony Tam

unread,
Jul 31, 2014, 10:12:18 AM7/31/14
to <swagger-swaggersocket@googlegroups.com>
Actually you can write your own authentication piece to add the header. Look at the swagger.js project and see the ApiKeyAuthentication. You have everything available to generate a signature and sign the request with a header. Give it a shot and post back any questions. 

j3d

unread,
Aug 1, 2014, 5:15:21 PM8/1/14
to swagger-sw...@googlegroups.com
OK, thank you very much for you support :-)
j3d


On Thursday, July 31, 2014 4:12:18 PM UTC+2, tony tam wrote:
Actually you can write your own authentication piece to add the header. Look at the swagger.js project and see the ApiKeyAuthentication. You have everything available to generate a signature and sign the request with a header. Give it a shot and post back any questions. 

On Jul 31, 2014, at 4:19 AM, "Ron" <web...@gmail.com> wrote:

Basically, what you want is to add another header parameter. This can be done either as a header parameter per operation or as an authorization scheme with a header-typed api key.

As for 'make Swagger sign the request body' - that's not something Swagger does.
I assume that when you say Swagger here, you mean the UI, and just like any other client that you'd have to tell it to do so, so you would need to tell Swagger-UI to do it with changes to its code. This is definitely doable.
On 31 July 2014 08:46, j3d <aga...@gmail.com> wrote:
Hello,

Till now I've used a GUID as the API key and just compared the api_key header with the key provided via Swagger-ui... but now it is time to get serious so I'm implementing a private/public key mechanism where I'll provide two headers: one containing the public api_key (as before) and another one containging the HMAC signature generated by hashing the request body.

When the backend receives the requests, it uses the public API key (api_key header) to retrieve the secret key from the database and then hashes the body of the incoming request. If the resulting hash matches with the signature contained in the request headers, then the request is accepted, otherwise it is rejected.

The question is: how do I make Swagger sign the request body and put the calculated hash in the request headers?

Thanks,
j3d

--
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 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.

j3d

unread,
Aug 2, 2014, 12:43:32 PM8/2/14
to swagger-sw...@googlegroups.com
... If I'm understanding well (I'm really not a CoffeeScript expert) I should create a CustomAuthorization in swagger.js and then add the following statement in my index.html:

window.authorizations.add("request_signature", new CustomAuthorization("request_signature");

Once the user provides the api_key in the Swagger UI, I need to
  1. Read the secret from MongoDB using the api_key as the selector
  2. Sign the request with the secret
  3. Add the signature to the request headers
Am I going to the right direction?

Any input is really appreciated ;-)
j3d

On Thursday, July 31, 2014 4:12:18 PM UTC+2, tony tam wrote:
Actually you can write your own authentication piece to add the header. Look at the swagger.js project and see the ApiKeyAuthentication. You have everything available to generate a signature and sign the request with a header. Give it a shot and post back any questions. 

On Jul 31, 2014, at 4:19 AM, "Ron" <web...@gmail.com> wrote:

Basically, what you want is to add another header parameter. This can be done either as a header parameter per operation or as an authorization scheme with a header-typed api key.

As for 'make Swagger sign the request body' - that's not something Swagger does.
I assume that when you say Swagger here, you mean the UI, and just like any other client that you'd have to tell it to do so, so you would need to tell Swagger-UI to do it with changes to its code. This is definitely doable.
On 31 July 2014 08:46, j3d <aga...@gmail.com> wrote:
Hello,

Till now I've used a GUID as the API key and just compared the api_key header with the key provided via Swagger-ui... but now it is time to get serious so I'm implementing a private/public key mechanism where I'll provide two headers: one containing the public api_key (as before) and another one containging the HMAC signature generated by hashing the request body.

When the backend receives the requests, it uses the public API key (api_key header) to retrieve the secret key from the database and then hashes the body of the incoming request. If the resulting hash matches with the signature contained in the request headers, then the request is accepted, otherwise it is rejected.

The question is: how do I make Swagger sign the request body and put the calculated hash in the request headers?

Thanks,
j3d

--
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 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.

tony tam

unread,
Aug 2, 2014, 6:53:54 PM8/2/14
to swagger-sw...@googlegroups.com

Yes, you don’t need to use coffeescript for this.

To make your own request signer, just make a class following this prototype:

var CustomRequestSigner = function(name) {
 
this.name = name;
};

CustomRequestSigner.prototype.apply = function(obj, authorizations) {
 
var hashFunction = this._btoa;
 
var hash = hashFunction(obj.url);

  obj
.headers["signature"] = hash;
 
return true;
};



This example takes the URL and simply computes the base 64 encoding of it—of course you’d use your own magic function.  But once done, it will add a header called “signature” with that value.

To apply the function, simply add it when initializing swagger-ui or swagger.js:

window.authorizations.add(“specialSignature", new CustomRequestSigner(“specialSignature");

and it’ll fire on any request against an operation with either NO authorizations specified on it (meaning, apply everything) or any operations that request that authorization explicitly:

implicit:

  "apis": [
   
{
     
"path": "/pet/{petId}",
     
"operations": [
       
{
         
"method": "GET",


explicit:

  "apis": [
   
{
     
"path": "/pet/{petId}",
     
"operations": [
       
{
         
"method": "GET",
         
"authorizations": {
           
"specialSignature": {}
         
},

tony tam

unread,
Aug 2, 2014, 7:16:03 PM8/2/14
to swagger-sw...@googlegroups.com

j3d

unread,
Aug 3, 2014, 2:26:38 PM8/3/14
to swagger-sw...@googlegroups.com
Hi Tony,

Thank you very much. It looks simply GREAT!

I've started working on it and as I told you I need to add two request headers:

Api_key f156a58c-9872-553f-ab26-a1b7777b5c14
Secret AGJ23454e#DE...

I already have a custom request header:

Authorization: Token eyJhbGciOiJIUzI1NiIsInR5cCI6Imp3dFwvYXV0aCJ9.eyJzdWIiOiI1M2RlMDRmNjU1MDUwMDc5MDU0MzEyNGYiLCJhdWQiOlsiaHR0cDpcL1wvbG9jYWxob3N0OjkwMDBcL2F1dGgiXSwiaXNzIjoiaHR0cDpcL1wvbG9jYWxob3N0OjkwMDAiLCJqdGkiOiI1M2RlNTc0ODE1MDgwMDU2MDhiNjE1OTciLCJ1c3IiOiJzdXBlcnVzZXIiLCJpYXQiOjE0MDcwODAyNjQsImFjYyI6IntcImlkXCI6XCI1M2RlMDRmNjU1MDUwMDU1MDU0MzEyNGVcIixcInVzZXJJZFwiOlwiNTNkZTA0ZjY1NTA1MDA3OTA1NDMxMjRmXCIsXCJvcGVuaW5nVGltZVwiOlwiMjAxNC0wOC0wM1QwOTo0NjozMS4wMjZaXCIsXCJyb2xlc1wiOlsxLjBdfSJ9.DH7c9jk7i3Gf4JTsLk4l6vM6RD-R_tlx4DXkbLWISek

... this is a JWT (Json Web Token)

Well, Swagger puts the token in the request headers as expected... but it doesn't the Api_key - this is very strange because it did. I did some debugging in swagger.js and ApiKeyAuthorization.prototype.apply correctly adds the Api_key element to obj.headers (line 1519). My index.html looks like this:

 56     var key = "f156a58c-9872-553f-ab26-a1b7777b5c14";
 57     log("added key " + key);
 58     window.authorizations.add("key", new ApiKeyAuthorization("api_key", key, "header"));
 59 
 60     $('#input_authToken').change(function() {
 61       key = $('#input_authToken')[0].value;
 62       if (key && key.trim() != "") {
 63         log("added key " + key);
 64         window.authorizations.add("key", new ApiKeyAuthorization("Authorization", "Token " + key, "header"));
 65       }
 66     })

Am I missing something? Could that be a regression?

Thank,
j3d

Tony Tam

unread,
Aug 3, 2014, 3:00:11 PM8/3/14
to <swagger-swaggersocket@googlegroups.com>
The only way the keys won't be sent is if they have the same name (they're stored in a hash) or if the operation doesn't declare them to be required. Do you have an authorizations key defined on the operation?
To unsubscribe from this group and stop receiving emails from it, send an email to swagger-swaggers...@googlegroups.com.

j3d

unread,
Aug 3, 2014, 3:45:41 PM8/3/14
to swagger-sw...@googlegroups.com
Do you mean the Annotations in my Scala code? No.

I just this line in index.html:

window.authorizations.add("key", new ApiKeyAuthorization("api_key", key, "header"));

I did the same for my token...

window.authorizations.add("key", new ApiKeyAuthorization("Authorization", "Token " + key, "header"));

... and every request has the Authorization header.

Is the api_key behavior different?

j3d

unread,
Aug 3, 2014, 3:49:20 PM8/3/14
to swagger-sw...@googlegroups.com
I've also tried to add this in the initialization code in index.html:

    $(function () {
        window.swaggerUi = new SwaggerUi({
        ...
        apiKey: "f156a58c-9872-553f-ab26-a1b7777b5c14",

Doing this, only the first request contains the api_key header.
Reply all
Reply to author
Forward
0 new messages