Post tweets on own Twitter account using /1.1/statuses/update.json fails, Could not authenticate you - http-post

Dears
I have invested quite some time in trying to post tweets to my own twitter user account from my web site without using any ready-made solutions.
The web site is given read/write access on app.twitter.com and i have regenerated all keys.
I am following the Twitter API instructions referring to endpoint "POST /1.1/statuses/update.json"
I have double checked all my objects and am still getting
response =--- !ruby/object:Net::HTTPUnauthorized
http_version: '1.1'
code: '401'
message: Authorization Required
header:
connection:
- close
content-length:
- '89'
content-type:
- application/json; charset=utf-8
date:
- Wed, 18 Oct 2017 15:28:19 GMT
server:
- tsa_o
set-cookie:
- personalization_id="v1_pxDMvL5ZrViFDcn8AfFemw=="; Expires=Fri, 18 Oct 2019 15:28:19
UTC; Path=/; Domain=.twitter.com
- guest_id=v1%3A150834049962807489; Expires=Fri, 18 Oct 2019 15:28:19 UTC; Path=/;
Domain=.twitter.com
strict-transport-security:
- max-age=631138519
x-connection-hash:
- '05228a7a2026efc93a8a2d4b1a8c6460'
x-response-time:
- '142'
x-tsa-request-body-time:
- '1'
body: '{"errors":[{"code":32,"message":"Could not authenticate you."}]}'
read: true
uri:
decode_content: true
socket:
body_exist: true
I want to send a simple "Hello" from my web site to my twitter account and have double checked all parts which will be presented below.
Also, same logic is used to authenticate me on my web site using my twitter account. So I know authorization (3-legs) works properly.
for posting tweets with my rails app, I have tried both 1) posting the tweet using my app's consumer and access token pairs without going all the authorization steps as well as 2) guiding myself to twitter for explicitly re-authorizing my web site to post the tweet. Both scenarios lead to Error 401. Everything works, except the actual tweeting step.
Any help is very much appreciated. Please note, I am not interested in using a gem and have read thoroughly the associated API documentation.
Here all the constituents of my post request :
Parameter String:
include_entities=true&
oauth_consumer_key=Xffffffffffffffffffffffff&
oauth_nonce=1vGbvxCqsfGi47L7ecpRnwA33fEojFoy6J2hkRpa8&
oauth_signature_method=HMAC-SHA1&
oauth_timestamp=1508340584&
oauth_token=4444444444-GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG&
oauth_version=1.0&
status=Hello
signature base string:
POST&
https%3A%2F%2Fapi.twitter.com%2F1.1%2Fstatuses%2Fupdate.json&
include_entities%3Dtrue%26
oauth_consumer_key%3DXffffffffffffffffffffffff%26
oauth_nonce%3D1vGbvxCqsfGi47L7ecpRnwA33fEojFoy6J2hkRpa8%26
oauth_signature_method%3DHMAC-SHA1%26
oauth_timestamp%3D1508340584%26
oauth_token%3D4444444444-GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG%26
oauth_version%3D1.0%26
status%3DHello
signing key:
W6SzwsKSXwFpl8tb0UNJFoCTW6crf6p3JaS8GipJMErofZVLAA&ENxK6XHG8h2EI7dOeSL0fABJzqnzs7FhP6QirBbXvd0br
signature:
0zx68mHx/SxhHkoRpaqZmO8iC2s=
header string:
OAuth oauth_consumer_key="Xffffffffffffffffffffffff",
oauth_nonce="1vGbvxCqsfGi47L7ecpRnwA33fEojFoy6J2hkRpa8",
oauth_signature="0zx68mHx%2FSxhHkoRpaqZmO8iC2s%3D",
oauth_signature_method="HMAC-SHA1",
oauth_timestamp="1508340584",
oauth_token="4444444444-GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG",
oauth_version="1.0"
POST REQUEST
request =--- !ruby/object:Net::HTTP::Post
method: POST
request_has_body: true
response_has_body: true
uri:
path: "/1.1/statuses/update.json?include_entities=true"
decode_content: true
header:
content-type:
- application/x-www-form-urlencoded
authorization:
- OAuth oauth_consumer_key="Xffffffffffffffffffffffff", oauth_nonce="1vGbvxCqsfGi47L7ecpRnwA33fEojFoy6J2hkRpa8",
oauth_signature="0zx68mHx%2FSxhHkoRpaqZmO8iC2s%3D", oauth_signature_method="HMAC-SHA1",
oauth_timestamp="1508340584", oauth_token="4444444444-GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG",
oauth_version="1.0"
host:
- api.twitter.com
accept-encoding:
- gzip;q=1.0,deflate;q=0.6,identity;q=0.3
accept:
- "*/*"
user-agent:
- Ruby
body: '{"status":"Hello"}'
body_stream:
body_data:

I finally got it to work. Several issues existed. Not with the signatures and the authorization headers. Instead issues existed in the time stamp used, which was not synchronized properly and also not in GMT as twitter is expecting. I synchronized my system clock against time.google.com and this part was done. Now, there was also an issue about the header which needed also sorting, contrary to twitter's own docs talking about sorting in the context of the signature base string only. I found out that also the extended header needs sorting. Extended because it contains the tweet itself which is not part of the signature calculation. once this part was built in posting the tweet was successful

Related

QuickBooks API example shows usage of "curl" but it actually doesn't work or am I missing something

According to QuickBooks Ruby API documentation, it provides an example of using curl to submit a POST request to the authorization url obtained from Step 1, but right underneath it, it shows that if the web application doesn't support browsers, to use Playground or a web component.
My question is – is it actually possible to use the curl command as shown in the example? If I take the exact URL and try to establish a POST request, I get the following results:
bash-3.2$ curl -X POST "https://appcenter.intuit.com/connect/oauth2?client_id=[redacted]&redirect_uri=http%3A%2F%2Flocalhost&response_type=code&scope=com.intuit.quickbooks.accounting&state=be17472c59724eb46bfe2690"
<html>
<head><title>301 Moved Permanently</title></head>
<body>
<center><h1>301 Moved Permanently</h1></center>
<hr><center>nginx</center>
</body>
</html>
bash-3.2$
Obviously it's trying to redirect to another URL, but the API documentation doesn't show the usage of the -L parameter to follow redirects. If I try to provide the -L parameter for curl to follow redirects, then I get the following response:
bash-3.2$ curl -X POST "https://appcenter.intuit.com/connect/oauth2?client_id=[redacted]&redirect_uri=http%3A%2F%2Flocalhost&response_type=code&scope=com.intuit.quickbooks.accounting&state=be17472c59724eb46bfe2690" -L
<HTML><HEAD>
<TITLE>Bad Request</TITLE>
</HEAD><BODY>
<H1>Bad Request</H1>
Your browser sent a request that this server could not understand.<P>
Reference #7.2500e8ac.1592267832.14229c52
</BODY>
</HTML>
Again, doesn't work even following redirects. If I append -I to the curl command, then I get the following:
bash-3.2$ curl -X POST "https://appcenter.intuit.com/connect/oauth2?client_id=[redacted]&redirect_uri=http%3A%2F%2Flocalhost&response_type=code&scope=com.intuit.quickbooks.accounting&state=be17472c59724eb46bfe2690" -LI
HTTP/2 301
date: Tue, 16 Jun 2020 00:37:17 GMT
content-type: text/html
content-length: 162
location: https://appcenter.intuit.com/app/connect/oauth2?client_id=[redacted]&redirect_uri=http%3A%2F%2Flocalhost&response_type=code&scope=com.intuit.quickbooks.accounting&state=be17472c59724eb46bfe2690
server: nginx
cache-control: no-store, no-cache, must-revalidate
strict-transport-security: max-age=3156000; includeSubDomains; preload
HTTP/2 302
date: Tue, 16 Jun 2020 00:37:17 GMT
content-type: text/plain;charset=utf-8
content-length: 406
location: https://accounts.intuit.com/index.html?partner_uid_button=google&offering_id=Intuit.sbg-fms.ippdevx&redirect_url=https%3A%2F%2Fappcenter.intuit.com%2Fapp%2Fconnect%2Foauth2%3Fclient_id%3D[redacted]%26redirect_uri%3Dhttp%253A%252F%252Flocalhost%26response_type%3Dcode%26scope%3Dcom.intuit.quickbooks.accounting%26state%3Dbe17472c59724eb46bfe2690
server: nginx
strict-transport-security: max-age=15552000
intuit_tid: 1-5ee8143d-29a68cec2ec922da5c6be528
x-spanid: ad76586b-a5ac-41bd-b2df-022148a5a78b
x-amzn-trace-id: Self=1-5ee8143d-3aa839e8b2cf25d846078238;Root=1-5ee8143d-29a68cec2ec922da5c6be528
x-dns-prefetch-control: off
x-download-options: noopen
x-content-type-options: nosniff
x-xss-protection: 1; mode=block
cache-control: private,no-cache,no-store,pre-check=0,post-check=0,must-revalidate
expires: -1
pragma: no-cache
set-cookie: hosted-shell=%7B%22clientId%22%3A%22a4676677-5191-4eca-873e-34a04b5b1dd4%22%7D; Path=/; Expires=Fri, 14 Jun 2030 00:37:17 GMT; Secure
vary: Accept, Accept-Encoding
cache-control: no-store, no-cache, must-revalidate
strict-transport-security: max-age=3156000; includeSubDomains; preload
HTTP/2 411
server: AkamaiGHost
mime-version: 1.0
content-type: text/html
content-length: 223
expires: Tue, 16 Jun 2020 00:37:17 GMT
date: Tue, 16 Jun 2020 00:37:17 GMT
If I take the same URL and request it via a web browser, then it just takes me to the redirect callback URL as it's supposed to. I can't figure out why curl isn't doing the same thing. I don't understand what it means by "web component" if I can't even replicate the same thing via curl. I also have another web module that I'm using for GET and POST requests, and they're bringing me to an HTTP200 but not the callback URL.
Any idea how I could accomplish getting this authorization token from the redirect callback URL like it does in the web browser? Here's another example of me trying to do this via the web component in the Ruby script:
[3] pry(#<QuickBooksAPI>)> grant_url
=> "https://appcenter.intuit.com/connect/oauth2?client_id=[redacted]&redirect_uri=http%3A%2F%2Flocalhost&response_type=code&scope=com.intuit.quickbooks.accounting&state=be17472c59724eb46bfe2690"
[4] pry(#<QuickBooksAPI>)> response = WebRequest.new.get_request(grant_url)
=> #<Net::HTTPMovedPermanently 301 Moved Permanently readbody=true>
[5] pry(#<QuickBooksAPI>)> response['Location']
=> "https://appcenter.intuit.com/app/connect/oauth2?client_id=[redacted]&redirect_uri=http%3A%2F%2Flocalhost&response_type=code&scope=com.intuit.quickbooks.accounting&state=be17472c59724eb46bfe2690"
[6] pry(#<QuickBooksAPI>)> response = WebRequest.new.get_request(response['Location'])
=> #<Net::HTTPFound 302 Found readbody=true>
[7] pry(#<QuickBooksAPI>)> response['Location']
=> "https://accounts.intuit.com/index.html?partner_uid_button=google&offering_id=Intuit.sbg-fms.ippdevx&redirect_url=https%3A%2F%2Fappcenter.intuit.com%2Fapp%2Fconnect%2Foauth2%3Fclient_id%3D[redacted]%26redirect_uri%3Dhttp%253A%252F%252Flocalhost%26response_type%3Dcode%26scope%3Dcom.intuit.quickbooks.accounting%26state%3Dbe17472c59724eb46bfe2690"
[8] pry(#<QuickBooksAPI>)> response = WebRequest.new.get_request(response['Location'])
=> #<Net::HTTPOK 200 OK readbody=true>
[9] pry(#<QuickBooksAPI>)> response.uri
=> #<URI::HTTPS https://accounts.intuit.com/index.html?partner_uid_button=google&offering_id=Intuit.sbg-fms.ippdevx&redirect_url=https%3A%2F%2Fappcenter.intuit.com%2Fapp%2Fconnect%2Foauth2%3Fclient_id%3D[redacted]%26redirect_uri%3Dhttp%253A%252F%252Flocalhost%26response_type%3Dcode%26scope%3Dcom.intuit.quickbooks.accounting%26state%3Dbe17472c59724eb46bfe2690>
This time it sends me to a 200 but it never actually sends me to the callback/redirect URL.
I'm just simply trying to complete step 2 but cannot do so without a browser it seems, even using "web components" and curl.
Am I just going to have to manually use OAuth Playground and continuously just refresh my token since my API is all backend and no front-end/user redirect, etc.?
The OAuth grant flow needs your end user to grant your authenticate your application before you call API using access tokens. So here is what you process would look like
Present your user with a Connect to Intuit (or equivalent) button
User Clicks on the button and goes through authentication on intuit website (seems like the first bit of code you have inserted in your question. This cannot be automated)
Intuit redirects to the redirect url with a authorization_code
Rest is automated - Your browser or server takes the authorization_code from the url, combines it with a few other parameters and requests for an access_token
You can then continue to use the access_token to make your calls on behalf of the end user.
From Step3. onwards you can use curl to process all of it. Hope this helps :)
EDIT
No, In your case you would use OAuth differently. Using the Oauth Playground will take create an initial access_token for you. Steps 1-4 are taken care of.
Now you can use this token to authenticate all your API calls. However, the token will expire. So when you do get an expired response then you have to do a curl to fetch a new token using the info here...
https://developer.intuit.com/app/developer/qbo/docs/develop/authentication-and-authorization/oauth-2.0#refresh-the-token

JMeter NTLM authentication failing

I'm relatively new to JMeter, but I am having a hard time getting an HTTP Sampler to land on a secured webpage. I think it requires NTLM authentication, so I used the HTTP Authorization Manager to pass credentials as specified in the BlazeMeter guide
My Authorization Manager has the following values:
Base URL: https:// [test site]
Username: [my user name]
Password: [my password]
Domain: Same as base URL
Mechanism: BASIC_DIGEST
However, I just get a 401 error (see Sampler Message below)
Thread Name: Thread Group 1-1
Sample Start: 2018-02-21 15:55:18 PST
Load time: 26
Connect Time: 0
Latency: 26
Size in bytes: 1602
Sent bytes:229
Headers size in bytes: 309
Body size in bytes: 1293
Sample Count: 1
Error Count: 1
Data type ("text"|"bin"|""): text
Response code: 401
Response message: 401
Response headers:
HTTP/1.1 401 401
Content-Type: text/html
Content-Language: en
Server: Microsoft-IIS/7.5
WWW-Authenticate: Negotiate
WWW-Authenticate: NTLM
WWW-Authenticate: Basic realm="BasicSecurityFilterProvider"
X-Powered-By: ASP.NET
Date: Wed, 21 Feb 2018 23:55:18 GMT
Connection: close
Content-Length: 1293
HTTPSampleResult fields:
ContentType: text/html
DataEncoding: iso-8859-1
I tried the following, but still get a 401 error. Any suggestions?
Changing all HTTP Request implementations to HTTPClient4
Setting httpclient4.auth.preemptive=true in the user.properties
Enable Use KeepAlive option
As per Windows Authentication with Apache JMeter guide you should replace Domain to not to be your base URL but rather Windows Domain name. As per the referenced guide:
Domain: should be “what you see in Windows Security pop-up” as this is what real browsers do. If you are uncertain you can type a fully qualified domain name into that field.
You can also figure out your domain name by running systeminfo command like:
systeminfo | find "Domain"

Browser serving an obsolete Authorization header from cache

I'm experiencing my client getting logged out after an innocent request to my server. I control both ends and after a lot of debugging, I've found out that the following happens:
The client sends the request with a correct Authorization header.
The server responds with 304 Not Modified without any Authorization header.
The browser serves the full response including an obsolete Authorization header as found in its cache.
From now on, the client uses the obsolete Authorization and gets kicked out.
From what I know, the browser must not cache any request containing Authorization. Nonetheless,
chrome://view-http-cache/http://localhost:10080/api/SearchHost
shows
HTTP/1.1 200 OK
Date: Thu, 23 Nov 2017 23:50:16 GMT
Vary: origin, accept-encoding, authorization, x-role
Cache-Control: must-revalidate
Server: 171123_073418-d8d7cb0 =
x-delay-seconds: 3
Authorization: Wl6pPirDLQqWqYv
Expires: Thu, 01 Jan 1970 00:00:00 GMT
ETag: "zUxy1pv3CQ3IYTFlBg3Z3vYovg3zSw2L"
Content-Encoding: gzip
Content-Type: application/json;charset=utf-8
Content-Length: 255
The funny server header replaces the Jetty server header (which shouldn't be served for security reasons) by some internal information - ignore that. This is what curl says:
< HTTP/1.1 304 Not Modified
< Date: Thu, 23 Nov 2017 23:58:18 GMT
< Vary: origin, accept-encoding, authorization, x-role
< Cache-Control: must-revalidate
< Server: 171123_073418-d8d7cb0 =
< ETag: "zUxy1pv3CQ3IYTFlBg3Z3vYovg3zSw2L"
< x-delay-seconds: 3
< Content-Encoding: gzip
This happens in Firefox, too, although I can't reproduce it at the moment.
The RFC continues, and it looks like the answer linked above is not exact:
unless a cache directive that allows such responses to be stored is present in the response
It looks like the response is cacheable. That's fine, I do want the content to be cached, but I don't want the Authorization header to be served from cache. Is this possible?
Explanation of my problem
My server used to send the Authorization header only when responding to a login request. This used to work fine, problems come with new requirements.
Our site allows users to stay logged in arbitrarily long (we do no sensitive business). We're changing the format of the authorization token and we don't want to force all users to log in again because of this. Therefore, I made the server to send the updated authorization token whenever it sees an obsolete but valid one. So now any response may contain an authorization token, but most of them do not.
The browser cache combining the still valid response with an obsolete authorization token comes in the way.
As a workaround, I made the server send no etag when an authorization token is present. It works, but I'd prefer some cleaner solution.
The quote in the linked answer is misleading because it omitted an important part: "if the cache is shared".
Here's the correct quote (RFC7234 Section 3):
A cache MUST NOT store a response to any request, unless: ... the Authorization header field (see Section 4.2 of [RFC7235]) does not appear in the request, if the cache is shared,
That part of the RFC is basically a summary.
This is the complete rule (RFC7234 Section 3.2) that says essentially the same thing:
A shared cache MUST NOT use a cached response to a request with an Authorization header field (Section 4.2 of [RFC7235]) to satisfy any subsequent request unless a cache directive that allows such responses to be stored is present in the response.
Is a browser cache a shared cache?
This is explained in Introduction section of the RFC:
A private cache, in contrast, is dedicated to a single user; often, they are deployed as a component of a user agent.
That means a browser cache is private cache.
It is not a shared cache, so the above rule does not apply, which means both Chrome and Firefox do their jobs correctly.
Now the solution.
The specification suggests the possibility of a cached response containing Authorization to be reused without the Authorization header.
Unfortunately, it also says that the feature is not widely implemented.
So, the easiest and also the most future-proof solution I can think of is make sure that any response containing Authorization token isn't cached.
For instance, whenever the server sees an obsolete but valid Authorization token, send a new valid one along with Cache-Control: no-store to disallow caching.
Also you must never send Cache-Control: must-revalidate with Authorization header because the must-revalidate directive actually allows the response to be cached, including by shared caches which can cause even more problems in the future.
... unless a cache directive that allows such responses to be stored is present in the response.
In this specification, the following Cache-Control response directives (Section 5.2.2) have such an effect: must-revalidate, public, and s-maxage.
My current solution is to send an authorization header in every response; using a placeholder value of - when no authorization is wanted.
The placeholder value is obviously meaningless and the client knows it and happily ignores it.
This solution is ugly as it adds maybe 20 bytes to every response, but that's still better than occasionally having to resend a whole response content as with the approach mentioned in my question. Moreover, with HTTP/2 it'll be free.

Using Active Directory roles while accessing a website from JMeter

In our company the web app that we are testing uses the active directory roles assigned to the user for accessing the website.
Edit:
Important information that I forgot to mention is that, while accessing the website I am not prompted for the username and password. The website is only displayed if I have the correct Active Directory role assigned to my user profile.
For Example,
Opening IE as myself - able to access the website.
Opening IE as a service account (with required Active Directory roles) - able to access the website.
Opening IE as a different user outside my project - not able to access the website.
I have tried (skeptically, desperate to get it working) Basic/ Kerberos Authorization in the HTTP Authorization Manager and even running JMeter as that service account still no luck. I keep getting the below
Thread Name: Users 1-1
Sample Start: 2017-04-26 17:08:18 CDT
Load time: 83
Connect Time: 13
Latency: 83
Size in bytes: 438
Sent bytes:136
Headers size in bytes: 243
Body size in bytes: 195
Sample Count: 1
Error Count: 1
Data type ("text"|"bin"|""): text
Response code: 401
Response message: Unauthorized
Response headers:
HTTP/1.1 401 Unauthorized
Server: nginx/1.10.1
Date: Wed, 26 Apr 2017 22:08:18 GMT
Content-Type: text/html
Content-Length: 195
Connection: keep-alive
WWW-Authenticate: Negotiate
X-Frame-Options: deny
X-Content-Type-Options: nosniff
HTTPSampleResult fields:
ContentType: text/html
DataEncoding: null
I am just trying to find out if any one here has got the JMeter working in a similar scenario/ if any one can point me in the right direction to overcome this hurdle.
Thanks all for your help in advance.
You need to identify the exact implementation of the authentication in your application.
Given you receive WWW-Authenticate: Negotiate - this is definitely not Basic HTTP Auth.
Negotiate may stand either for NTLM or for Kerberos (or in some cases for both, i.e. if Kerberos is not successful it will fall back to NTLM) and JMeter needs to be configured differently for these schemes.
For example for NTLM you need to provide only credentials and domain in the HTTP Authorization Manager and for Kerberos you need to populate Realm and set your Kerberos settings (KDC and login config) under jaas.conf and krb5.conf files
See Windows Authentication with Apache JMeter article for more information and example configurations.

Token based authentication for user and separate module

I have 2 scenarios where I want to implement the token based authentication:
I want to implement token based authentication when a user logs in. i.e.. based on username and password , user should get a token and that token should be used with every request.
I have a separate independent module which has ID and secret Key. It has to communicate with server in specific interval. I want to implement token based authentication for this module also.
In both the cases token should have these properties:
It should be in payload.
It should have a timeout period
When token expires server should provide a new token,if the session is not expired else it should logout.
Is OAuth 2.0 right choice? If any other approach is better, Please tell me.
What should I do to solve this problem?
Which is the best place to put token in request -Payload or header? and Why?
OAuth 2.0 is a good choice for the requirements you mentioned: timeout period and refresh-ability.
Stormpath has an excellent OAuth2.0 implementation that gives you what you are looking for out of the box.
Stormpath has both remote and local OAuth2 Implementations and both are freely available. For the remote case you can rely on our backend using any REST client (http://docs.stormpath.com/guides/token-management/) and any of our SDKs. For the local case you can use our Servlet plugin to run a Web-app with out of the box OAuth2 support. Using the docs link above, you can find documentation for these resources.
Using the Stormpath Spring Boot integration, for instance, you could do something like this:
http -v --form POST http://localhost:8080/oauth/token \
> 'Origin:http://localhost:8080' \
> grant_type=password username=micah+demo.jsmith#stormpath.com password=<actual password>
(This example uses httpie to interact with a locally running Spring Boot instance). The line I've bolded above conforms to the OAuth2.0 spec for authenticating with usernames and passwords. What you get back is a response like:
HTTP/1.1 200 OK
Cache-Control: no-store
Content-Length: 325
Content-Type: application/json;charset=UTF-8
Date: Tue, 04 Aug 2015 16:02:08 GMT
Pragma: no-cache
Server: Apache-Coyote/1.1
Set-Cookie: account=eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiIxNDQyNmQxMy1mNThiLTRhNDEtYmVkZS0wYjM0M2ZjZDFhYzAiLCJpYXQiOjE0Mzg3MDQxMjgsInN1YiI6Imh0dHBzOi8vYXBpLnN0b3JtcGF0aC5jb20vdjEvYWNjb3VudHMvNW9NNFdJM1A0eEl3cDRXaURiUmo4MCIsImV4cCI6MTQzODk2MzMyOH0.wcXrS5yGtUoewAKqoqL5JhIQ109s1FMNopL_50HR_t4; Expires=Wed, 05-Aug-2015 16:02:08 GMT; Path=/; HttpOnly
{
"access_token": "eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiIxNDQyNmQxMy1mNThiLTRhNDEtYmVkZS0wYjM0M2ZjZDFhYzAiLCJpYXQiOjE0Mzg3MDQxMjgsInN1YiI6Imh0dHBzOi8vYXBpLnN0b3JtcGF0aC5jb20vdjEvYWNjb3VudHMvNW9NNFdJM1A0eEl3cDRXaURiUmo4MCIsImV4cCI6MTQzODk2MzMyOH0.wcXrS5yGtUoewAKqoqL5JhIQ109s1FMNopL_50HR_t4",
"expires_in": 259200,
"token_type": "Bearer"
}
This provides a bearer token that can be used on subsequent requests as well as an expiration. Plus, it has the advantage of being a JWT - JSON Web Token. The JWT is cryptographically signed to ensure that it hasn't been tampered with and it can be decoded to provide additional meta-information to your client, including user information, access controls and expiration.
You could do something very similar using the grant_type=authorization_code for interacting using an id and secret, such as for the independent module you mentioned.
This article goes into more detail on token authentication with Java.
Full disclosure: I am a Stormpath employee and I wrote the article referenced above.

Resources