My web service uses JWT-based authorization bearer token authentication:
HTTP clients send a valid POST to /v1/auth/signIn with a valid JSON request entity (includes username + password info)
If they authenticate successfully, that endpoint sends back an auth bearer token as an HTTP response header that (from curl) looks like:
Response from curl:
HTTP/1.1 200 OK
Date: Tue, 04 Sep 2018 01:18:28 GMT
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
X-Frame-Options: DENY
Access-Control-Expose-Headers: Authorization
Authorization: Bearer <big_huge_string>
Content-Length: 0
Subsequent service calls to authenticated endpoints just need to include the token as an HTTP request header whose key/name is Authorization and whose value is "Bearer <xyz>" (where <xyz>) is the <big_huge_string> that came back on the sign in call above. Pretty basic standard JWT stuff.
I'm trying to write a Postman collection that starts with a "Sign In Request" that successfully signs in and gets a JWT token from the service, and then adds the appropriate HTTP request header in each subsequent call. Any ideas as to how I can:
Extract the <big_huge_string> off the HTTP response header that I'll get back from my Sign In Request?; and then
How to save that <big_huge_string> as a variable and inject that as an HTTP request header for all subsequent calls?
Thanks in advance!
Update
Tried the suggestion:
Getting closer, but console.log(...) isn't printing anything to Postman (or at least I don't know where to look for it). I should mention I'm not using the Chrome Application version of Postman, but the standalone app/executable (Version 6.1.4):
Any ideas how/where I can get console.log(...) working? I'm concerned about just changing the test to:
pm.test("Can Extract JWT", function() {
var authHeader = pm.response.headers.toObject().Authorization;
pm.expect(authHeader).to.not.be.equal(null);
pm.globals.set('token', authHeader)
});
Without first seeing what that authHeader even is. Any ideas?!
Once you have that Token value you can reference it in each of the request headers using the {{token}} syntax. It's getting the sign in Auth header that's the harder part.
You could use pm.response.headers to get a list of the Headers and then extract out the value that you need.
This is returned as a list so maybe using something like Lodash or converting this to an object can help get the value you need. It would be something like pm.response.headers.toObject().Authorization - I haven't tried it so my syntax might be slightly wrong.
You can log the Headers out to the Postman console and narrow it down that way to - just wrap it in a Console.log() statement.
When you get that value, it's just a basic pm.globals.set('token, pm.response.headers.toObject().Authorization) to save this globally.
Related
So I was testing my website and I tried connecting with the TRACE http method. In response I got a massive string. I don't know what it is. Does anybody know what could it be and if it's some sort of vulnerability?
This is the string I'm talking about:
VFJBQ0UgLy5odHBhc3N3ZCBIVFRQLzEuMQ0KSG9zdDogd3d3LnNzZmt6LnNpDQpVc2VyLUFnZW50OiBNb3ppbGxhLzUuMCAoWDExOyBMaW51eCB4ODZfNjQ7IHJ2OjkxLjApIEdlY2tvLzIwMTAwMTAxIEZpcmVmb3gvOTEuMA0KQWNjZXB0OiB0ZXh0L2h0bWwsYXBwbGljYXRpb24veGh0bWwreG1sLGFwcGxpY2F0aW9uL3htbDtxPTAuOSxpbWFnZS93ZWJwLCovKjtxPTAuOA0KQWNjZXB0LUxhbmd1YWdlOiBlbi1VUyxlbjtxPTAuNQ0KQWNjZXB0LUVuY29kaW5nOiBnemlwLCBkZWZsYXRlDQpDb25uZWN0aW9uOiBrZWVwLWFsaXZlDQpDb29raWU6IGpzQ29va2llV2FybmluZ0NoZWNrPWRlY2xpbmVkDQpVcGdyYWRlLUluc2VjdXJlLVJlcXVlc3RzOiAxDQpDYWNoZS1Db250cm9sOiBtYXgtYWdlPTAsIG5vLWNhY2hlDQpPcmlnaW46IGh0dHA6Ly93d3cuc3Nma3ouc2kNClByYWdtYTogbm8tY2FjaGUNCg0K
It's a Base64 encoded string. Decoded it looks like this:
TRACE /.htpasswd HTTP/1.1
Host: www.ssfkz.si
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:91.0) Gecko/20100101 Firefox/91.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
Cookie: jsCookieWarningCheck=declined
Upgrade-Insecure-Requests: 1
Cache-Control: max-age=0, no-cache
Origin: http://www.ssfkz.si
Pragma: no-cache
Which per se does not really look like a security flaw and much rather like a basic implementation of the TRACE http method which states that the contents of the request shall be reflected in their entirety in the response body.
Interesting note though, looking at the specification:
A client MUST NOT generate header fields in a TRACE request containing sensitive data that might be disclosed by the response. For example, it would be foolish for a user agent to send stored user credentials [RFC7235] or cookies [RFC6265] in a TRACE request. The final recipient of the request SHOULD exclude any request header fields that are likely to contain sensitive data when that recipient generates the response body.
So ideally the response should not have contained the Cookie header (to fully comply with the specification by my understanding the client you used to send the requests should not have included them in the first place however).
I've read many question on stackoverflow about passing parameters with GET and POST methods, but none of them satisfied my curiosity.
I use GETs to retrieve data passing parameters as path/query params and use POSTs to save data passing parameters as request body with Content-Type: application/json and sometimes request body + path/query params (depending on other APIs I've created for simmetry purpose only).
My question is when to use Content-Type: application/x-www-form-urlencoded. Say I want to call a POST without a request body of Content-Type: application/json but with params, do I have to use the application/x-www-form-urlencoded Content-Type or I can use path/query params as best practice?
What's the difference between sending data as path/query params and key-value params with Content-Type: application/x-www-form-urlencoded? Does the data size have to do with it?
What's the difference between sending data as path/query params and key-value params with Content-Type: application/x-www-form-urlencoded?
Consider this example
PUT /example?a=b&c=d
Content-Type: application/x-www-form-urlencoded
d=e&f=g
What's happening here? This is a request that the server replace its current representation of the resource identified by
/example?a=b&c=d
With the payload. In other words, after successful processing, we would expect
GET /example?a=b&c=d
to produce a response like
200 OK
Content-Type: application/x-www-form-urlencoded
d=e&f=g
POST /example?a=b&c=d
Content-Type: application/x-www-form-urlencoded
d=e&f=g
For POST, it's the same idea, except that instead of "replace the current representation", POST stands in for "process the payload according to the specific semantics of /example?a=b&c=d".
GETs to retrieve data passing parameters as path/query params
It might help to reframe your thinking here. We use GET to retrieve the current representation of a resource. We aren't passing parameters, we're passing a document (resource) identifier.
The fact that the origin server's implementation is going to parse that identifier is an implementation detail.
A URI Template is a compact sequence of characters for describing a
range of Uniform Resource Identifiers through variable expansion.
-- RFC 6570
I want to call a POST without a request body of Content-Type: application/json but with params, do I have to use the application/x-www-form-urlencoded Content-Type or I can use path/query params as best practice?
POST /example?a=b&c=d
Content-Type: application/json
{"d":"e","f":"g"}
Is a perfectly normal HTTP request.
Content-Type describes the payload only - it has nothing at all to do with the target URI, and how information might be encoded within it.
I am trying to get an access token from the Pay Pal REST API, following this article: https://developer.paypal.com/docs/api/overview/#get-an-access-token
My request looks like this:
POST https://api.paypal.com/v1/oauth2/token HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Accept: application/json
Accept-Language: en_US
Authorization: Basic [redacted]
Host: paypal.com
Content-Length: 31
Expect: 100-continue
Connection: Keep-Alive
grant_type=client_credentials
But I keep getting 400 Bad Request with the following response data:
{ “error”: “unsupported_grant_type”, “error_description”: “unsupported grant_type” }
I can't figure out why - as far as I can see, I've followed the instructions exactly!
Their "Merchant Techincal Support" has been absolutely no help.
TLDR; PayPal REST API's GetAccessToken endpoint does not trim whitespace.
I solved it. The astute will notice the following discrepancy:
Content-Length: 31
...
grant_type=client_credentials
The data is only 29 characters - the extra two being \r\n carriage return and line feed.
In code (I'm using C#/.NET) this was a matter of changing:
writer.WriteLine("grant_type=client_credentials");
To
writer.Write("grant_type=client_credentials");
This corrected the issue.
If you're using Postman, add it to Params tab. Like so:
I've generated Access Tokens in the Settings/..../ Keys and Access Tokens page and now have a
Consumer Key
Consumer Secret Key
Owner ID (even though this was probably already generated)
Access Token
Access Token Secret
and am using a rest client to test being able to pull the latest 3 statuses using this api end point
https://api.twitter.com/1.1/statuses/user_timeline.json?user_id=userIdHere&count=3
as well as the following headers
Accept: /
Connection: close
User-Agent: OAuth gem v0.4.4
Content-Type: application/x-www-form-urlencoded
Content-Length: 76
Host: api.twitter.com
Authorization: OAuth
oauth_consumer_key=
oauth_signature=
oauth_signature_method=
oauth_timestamp=
oauth_token=
oauth_version=
obviously the 'userIdHere' in the end point address (above) is substituted with my username (i know i can also use my user_id, but that's beside the point) as well as the 'Authorization' values being substituted for real values. That's where my question lies...
What is the mapping for each of the 'oauth...' authorization parameters to their associated Twitter generated and provided Token or key(s) (which were mention near the top of the post)?
I keep getting a '400 Bad Request' response and feel that it is the authorization that is failing in that the permutations of key placements is incorrect. I do not know which value goes to which 'oauth...' value
finally, the structure of the 'Authorization' parameter header is as follows (as per instruction here from the Twitter EXAMPLE) as one line string value
OAuth oauth_consumer_key="xvz1evFS4wEEPTGEFPHBog", oauth_nonce="kYjzVBB8Y0ZFabxSWbWovY3uYSQ2pTgmZeNu2VS4cg", oauth_signature="tnnArxj06cWHq44gCs1OSKk%2FjLY%3D", oauth_signature_method="HMAC-SHA1", oauth_timestamp="1318622958", oauth_token="370773112-GmHxMAgYyLbNEtIKZeRNFsMKPR9EyMZeS9weJAEb", oauth_version="1.0"
)
I am just trying to use a GET to get the last 3 statuses and have not been able to. Also, i plan to switch the values to Environmental Variables, but that doesn't matter yet..
UPDATE
using Postman now, and it's better at mapping, but now am getting
{
"errors": [
{
"code": 32,
"message": "Could not authenticate you."
}
]
}
For the Postman part make sure that you leave Timestamp and nonce empty and hit "update request" before you hit send. That will generate timestamp and nonce - otherwise you will get authorization failures every time. I just tried it with my twitter API credentials and it works.
For Oauth gem code, I find it strange that you have a Content-Type and a Content-Length header for a GET request. Looks like the 400 Bad request could be because you are attempting to do a POST to an endpoint that only supports GET. Indeed when I try to do a POST to that endpoint it tells me.
{
"errors": [
{
"code": 86,
"message": "This method requires a GET or HEAD."
}
]
}
So the 400 is actually good news - it means that authorization works, you are just calling the API in the wrong way.
How to indicate that one particular header of a request is optional with the markdown of apiary?
My code:
Request
The apiKey can be passed in the header (note the camelcase for "apiKey")
The Content-Encoding: gzip is optional, only if you gzip the entity
Headers
apiKey: `42452-eofefo-4534535` (optional)
Content-Type: application/json
Content-Encoding: gzip (optional)
Is the above ok?
As of January 2016, it's not possible.
On the other hand—if you go to the API Blueprint Roadmap, there's MSON Parameters and Headers feature which is currently in the RFC stage; this will enable you to describe HTTP Headers in the MSON syntax and mark each HTTP Header as required/optional (see below).
+ Response 200 (application/json)
+ Headers
+ Date (Date, optional) - Date at which the message was originated
Hoping MSON Headers will land soon.