Spring Security sessionID as token configuration - spring

I am implementing a login process using Spring Security + Spring session to build login functionality for a REST like backend service that needs to create/mantain a session.
I am not sure if I am approaching the solution the right way since I am using a custom endpoint to create the session manually. Maybe the session creation needs to be done in the Authorization method itself? Or maybe there is a way to have spring create the session after some request validations in the backend? I am using a custom filter and provider for this.
Also with my current configuration, I am having an issue since the backend API is creating a new session with every request, even when it should return 401.
The requirements of this solution is as follows:
The clients will login to a third party authentication/authorization provider. Once validated, the provider will issue an access token.
The API must validate the client's access token with the third party provider. Once validated, the API must create a session and return a new token (or sessionID) to the clients.
Future calls to the API should include the token (or sessionID) in the header/cookie so the API gets the session of the client.
The big question here is: Is there a common approach to follow for using token based authentication linked to a user session? If so, what if I need to do custom validations before having spring session create the session, and also add custom attributes to this session?
My code is located here: https://github.com/munilvc/api-session/tree/master/src/main/java/com/munilvc/poc/security
For instance, some sample executions:
1) Execute custom login:
$ curl -X POST http://localhost:8080/app-api/login/createsession -v
> POST /app-api/login/createsession HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.49.1
> Accept: */*
>
< HTTP/1.1 200
< x-auth-token: 15a06ce8-5b34-401a-a05f-a0d933926245
< Content-Type: application/json;charset=UTF-8
< Transfer-Encoding: chunked
< Date: Tue, 29 Aug 2017 01:28:24 GMT
<
171{"username":"username1"}
2) Call another endpoint with provided x-auth-token:
NOTE the x-auth-token is refreshed in the response. (means a new session is created - This is what we want to avoid, this also happens when response is 401)
$ curl -X GET http://localhost:8080/app-api/accounts/2 -H "x-auth-token:15a06ce8-5b34-401a-a05f-a0d933926245" -v
> GET /app-api/accounts/2 HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.49.1
> Accept: */*
> x-auth-token:15a06ce8-5b34-401a-a05f-a0d933926245
>
< HTTP/1.1 200
< 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
< x-auth-token: 42a5db80-e5e1-4127-bd85-e468af4a8fb2
< Content-Type: application/json;charset=UTF-8
< Transfer-Encoding: chunked
< Date: Tue, 29 Aug 2017 01:29:08 GMT
<
870{"id":3,"name":"Account 3"}
PS: I am not sure if I am allowed to provide a link to the code in stack overflow. If not, I can paste the code here as well.
Thank you very much!

Based on your requirements, OpenID Connect can be used to authenticate the end-user and authorize a client which will then receive an AccessToken. Then the AccessToken may be used to call the back-end API's (Resource Servers).
Take a look at this sample/guide on how to setup login within Spring Security 5 against an external OAuth 2.0 or OpenID Connect provider. This will meet your requirement for logging into the application using an external provider and creating a secure session within Spring Security.
Now that you are logged in to the application and the client has an AccessToken, the client can use that AccessToken in the request (Authorization Header) to call the back-end API's (Resource Servers). The Resource Server should be setup to validate the incoming AccessToken. Take a look at this sample (master and jwt-support branches) on how to configure a Resource Server.
I would strongly recommend becoming more familiar with OAuth 2.0 Authorization Framework and OpenID Connect Core 1.0.
Good luck!

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

Keycloak - Didn't find publicKey for specified kid

I have an application divided into frontend and backend services. The frontend has public acces, while the backend is confidential. When I'm trying to authorize to get response from my backend I'm getting the following error:
cache-control: no-cache, no-store, max-age=0, must-revalidate
content-length: 0
date: Fri, 06 Dec 2019 09:16:16 GMT
expires: 0
pragma: no-cache
vary: Origin, Access-Control-Request-Method, Access-Control-Request-Headers
www-authenticate: Bearer realm="my_realm", error="invalid_token", error_description="Didn't
find publicKey for specified kid", Bearer realm="my_realm", error="invalid_token",
error_description="Didn't find publicKey for specified kid"
x-content-type-options: nosniff
x-frame-options: DENY
x-xss-protection: 1; mode=block
Here's my configuration for both services:
Backend:
keycloak:
auth-server-url: http://localhost:8081/auth
realm: my_realm
resource: your-client-id
ssl-required: external
credentials.secret: your-client-secret
Frontend:
sso: {
url: 'http://localhost:8081/auth',
realm: 'my_realm',
clientId: 'your-frontend-client'
}
I'm using keycloak 7.0.1 along with Spring Security.
Am I missing any additional config for allowing authorization from public client?
You have to check multiple things
You need to check your client names are same in you application and keycloak.
Sometime Keycloak URL may incorrent it should be http OR https://<IP ADDRESS>:PORT/auth
Sometime its becuase of certificate as well
Please check the version of keycloak running and client jars you are using.
https://medium.com/#siweheee/keycloak-a-real-scenario-from-development-to-production-ce57800e3ba9
Keycloak: missing realm public key
Keycloak invalid_token Didn't find publicKey for specified kid
If you are using docker environment
KeyCloak must to be accessed from all clients by the same public
address for security reasons. This includes also the GUI server. It is
not possible to talk to Keycloak via a local IP address as the
security depends on the IP address.
https://github.com/hobbit-project/platform/issues/18

Cross-Origin Request Blocked while authenticating

I am trying to design an OAuth2 authentication system that secures a variety of backend APIs. I started by downloading and installing the three interconnected Spring Boot / Cloud / OAuth2 apps in this github project.
But my project requires two major architectural changes:
1.) The main portal UI must be running in Node.js, so that users can
view a public site and also login using a Node.js-hosted app that
makes REST calls to a backend authentication server, without feeling
like they are being redirected anywhere for authentication.
2.) My app requires multi-factor authentication, so I need to create (or
at least customize) my own endpoints on the `authserver` app instead
of relying to the standard password authentication endpoint.
What specific changes need to be made so that my Node.js-hosted UI app can successfully interact with the authserver app and the resource app?
At the moment, adding AngularJS login code to either my own Node.js portal app OR to the ui app in the github sample results in the FireFox console showing the following error messages when the AngularJS code tries to call the authserver app running on port 9000:
Cross-Origin Request Blocked: The Same Origin Policy disallows reading
the remote resource at http://localhost:9000/login-form. (Reason: CORS
header 'Access-Control-Allow-Origin' missing). <unknown>
Cross-Origin Request Blocked: The Same Origin Policy disallows reading
the remote resource at http://localhost:9000/login-form. (Reason: CORS
request failed).
The AngularJS code that calls the new /login-form endpoint that I added to the authserver endpoint is:
$scope.credentials = {};
$scope.loginError = false;
$scope.showLogin = false;
$scope.loginShow = function() {
$scope.showLogin = true;
console.log('filler to add break point for debugger.');
};
$scope.loginLocal = function() {
console.log('Just filler to add a break point in debugger.');
var funcJSON = { 'type': 'Message',
'content1': $scope.credentials.username,
'content2': $scope.credentials.password
};
console.log('filler to add break point.');
$http.post('http://localhost:9999/uaa/login-form', funcJSON).then(function(response) {
if(response.data.content1==='success'){
$scope.Oauthenticated = true;
console.log('filler to add a break point');
}else {
$scope.Oauthenticated = false;
$scope.loginError = true;
console.log('filler to add break point');
}
});
};
The FireFox debugger shows that the line of the above AngularJS code that throws the error in the FireFox console shown at top is:
$http.post('http://localhost:9999/uaa/login-form', funcJSON).then(function(response) {
I added a new /login-form end point to the AuthserverApplication.java file in the authserver app, and you can read my entire new AuthserverApplication.java file at a file sharing site by clicking on this link.
I am open to running the main portal UI app inside of Spring Boot. I have read that this would require using the #EnableSidecar annotation. However, I get the same error message above whether the new login form is run inside the Spring Cloud ui app from the github link above, or from my Node.js-hosted portal UI. So what do I need to change to set up a secure way of managing this authentication from my Node.js-hosted portal app?
ONGOING RESEARCH:
Per #Ulises' suggestion, I added code to override a method of AuthserverApplication.java. I also double checked the url and slightly altered the url for the $http.post(... call (which I changed in-line above in the OP to avoid confusion. The result is the same error in the FireFox console, plus an explicit log of the request in the Spring Boot log for the authserver app.
You can read my new AuthserverApplication.java class including #Ulises's suggestion at a file sharing site by clicking this link. The Node.js-hosted app that makes the call is running on port 7000.
And you can read the entire Spring Boot log for the request at a file sharing site by clicking on this link.
Similarly, when I change the suggested method to read:
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/login-form").allowedOrigins("http://localhost*");
}
I get the Spring Boot error log that you can read at a file sharing site by clicking on this link. And the Network tab of the FireFox debugger gives a 401 error, with the following raw headers:
Request headers:
Host: localhost:9999
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:38.0) Gecko/20100101 Firefox/38.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Origin: http://localhost:7000
Access-Control-Request-Method: POST
Access-Control-Request-Headers: content-type,x-requested-with
Connection: keep-alive
Pragma: no-cache
Cache-Control: no-cache
Response headers:
Cache-Control: no-cache, no-store, max-age=0, must-revalidate, no-store
Content-Type: application/xhtml+xml;charset=UTF-8
Date: Wed, 13 Apr 2016 09:32:40 GMT
Expires: 0
Pragma: no-cache, no-cache
Server: Apache-Coyote/1.1
Transfer-Encoding: chunked
WWW-Authenticate: Bearer realm="null", error="unauthorized", error_description="Full authentication is required to access this resource"
X-Frame-Options: DENY
X-XSS-Protection: 1; mode=block
x-content-type-options: nosniff
The same new error persists even when I add the following method to the LoginConfig inner class inside AuthserverApplication.java to try to get Spring Security to ignore the /login-form endpoint:
#Override
public void configure(WebSecurity webSecurity) throws Exception {
webSecurity.ignoring().antMatchers("/login-form", "/error");
}
I am currently reading the Spring OAuth2 Developer's Guide at this link, which refers to sample apps on github at this link. However, the sample apps use JSP, which is obsolete, and does not address the use case described in this OP.
In your AuthServerApplication override method addCorsMapping(CorsRegistry) from WebMvcConfigurerAdapter like this:
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/login-form").allowedOrigins("http://localhost:9000");
}
Or wherever origin you're calling it from. You can also use * for everything and/or add any fine-grained configuration

How can I get a list of calendar resources via Google API

I try to use fetch list of Calendar Resources (https://support.google.com/a/answer/60766?hl=en) from my company's Google Apps, using Google API. I try to use it using OAuth 2.0 Playground page (https://developers.google.com/oauthplayground). What I do:
1. I select scope & authorize API with my company's admin account and using this scope https://apps-apis.google.com/a/feeds/calendar/resource/
2. I xchange authorization code for tokens
3. I put a requested URL: https://apps-apis.google.com/a/feeds/calendar/resource/2.0/my-company-domain-url/
4. I send request and I get error:
HTTP/1.1 403 Forbidden
Alternate-protocol: 443:quic,p=1
Content-length: 207
X-xss-protection: 1; mode=block
X-content-type-options: nosniff
Transfer-encoding: chunked
Expires: Fri, 18 Dec 2015 22:09:43 GMT
Server: GSE
-content-encoding: gzip
Cache-control: private, max-age=0
Date: Fri, 18 Dec 2015 22:09:43 GMT
X-frame-options: SAMEORIGIN
Alt-svc: quic=":443"; ma=604800; v="30,29,28,27,26,25"
Content-type: text/html; charset=UTF-8
<HTML>
<HEAD>
<TITLE>You are not authorized to access this API.</TITLE>
</HEAD>
<BODY BGCOLOR="#FFFFFF" TEXT="#000000">
<H1>You are not authorized to access this API.</H1>
<H2>Error 403</H2>
</BODY>
</HTML>
I've already enabled this API in Developers Console.
Question: what else do I need to do to make it work, i.e. be able to fetch calendar resources list?
I was simply missing the enabled flag for Administrative API access, described here:
https://support.google.com/a/answer/60757?hl=en
second thing, more obvious is that only domain admins have access to this API.
Additionally, I've just found that in version 1.21 of Admin-SDK Java Client library (com.google.apis:google-api-services-admin-directory) Google added support for Calendar Resources! So all you need to do now is:
Directory.resources().calendars().list("my_customer").execute();
The scope is new: https://www.googleapis.com/auth/admin.directory.resource.calendar so one needs to authorize it API in Google Apps Admin console.
You might want to try this link, https://developers.google.com/google-apps/calendar/v3/reference/acl/list.
This should give you a list of resources.
Here is a link for the Overview info, https://developers.google.com/google-apps/calendar/v3/reference/acl.
I hope it helps.

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