it's quite simple to secure/protect an ASP.NET Web API with OWIN (Katana). Now, I'm looking for a Java library that offers OWIN-similar features, so that I can secure my Java-based Web APIs. Only GET and POST requests with a Bearer token in the header are allowed, otherwise a HTTP 401 should be returned. Therefore the library should be able to verify the Bearer token.
Any hint, link, reference, etc. is highly appreciated. Thanks!
Dominik
BearerToken.parse(String) in authlete-java-common covers the three ways to extract an access token described in RFC 6750 (Bearer Token Usage).
// Case 1:
// Extract an access token from 'Authorization' HTTP header.
// The value of 'Authorization' HTTP header.
String authorization = ...;
// Extract an access token from 'Authorization' HTTP header.
String accessToken = BearerToken.parse(authorization);
// Case 2:
// Extract an access token from the entity body of a POST request.
// Entity body formatted in 'application/x-www-url-encoded'.
String body = ...;
// Extract an access token.
String accessToken = BearerToken.parse(body);
// Case 3:
// Extract an access token from the query string of a GET request.
// Query string.
String query = ...;
// Extract an access token.
String accessToken = BearerToken.parse(query);
Maven:
<dependency>
<groupId>com.authlete</groupId>
<artifactId>authlete-java-common</artifactId>
<version>1.3</version>
</dependency>
It wouldn't take much time even if you implemented the same thing from scratch, though.
Source code -> BearerToken.java
Related
For my API testing, I have been getting the Authentication Token with the help of Postman. API uses OAuth2.0 for authentication.
While using Postman, I am entering the details like Token Name, Grant Type, Access Token Url, Client ID, Client Secret, Scope, Client Authentication. Once clicked on the Request Token, Bearer token is received and is updated in the Header of the request. Please refer the image attached.Getting OAuth2.0 bearer token with Postman
But now, I want to do it with Rest Assured using Java. Hence I want to know the code how do I get the Bearer token by using Rest Assured?
Assuming you are sending the client id secret and other details in the Query Parameters, for the GET and your response header access_token has the value you are looking.
public class Sample {
String oauth_token ;
#BeforeTest
public void sampletest() {
oauth_token = RestAssured.given().auth().basic("username", "password").
.queryParams("client_id", "client_id_value")
.queryParams("client_secret", "client_secret_value")
.queryParams("grant_type", "authorization_code")
.queryParams("redirect_uri", "https://someuritoredirect")
.queryParams("otherparams", "sampleparam")
.when().get("https://uri.to.get.hostname.com/oauth2/access_token")
.then()
.statusCode(200)
.extract().header("access_token");
}
}
I try to use Google Photos API to upload my images, base on the steps of the following link.
https://developers.google.com/photos/library/guides/upload-media
After following the Using OAuth 2.0 for Web Server Applications, I just get the Oauth2.0_token response(a JSON format with access_token, refresh_token...). However, after I put this token string with "Bearer " into request headers, the response is error 401, the error message is "code 16 Authentication session is not defined".
I cannot find any information to deal with it, thank for any help.
You probably have incorrect permissions. Make sure you request the token with the appropriate scope. For write-only access you need 'https://www.googleapis.com/auth/photoslibrary.appendonly'
src: https://developers.google.com/photos/library/guides/authentication-authorization#what-scopes
One reason this might be happening is that you initially authorized your user for read-only access. If you went through the authorization flow with a .readonly scope, your bearer token reflects that authorization (and the token is retained in your credentials file). If you change your scope but don't get a new auth token you will get this error when trying to upload. Simply redo the authorization flow with the new scope defined:
SCOPES = 'https://www.googleapis.com/auth/photoslibrary'
store = file.Storage('path_to_store')
if not creds or creds.invalid:
flow = client.flow_from_clientsecrets('google_credentials.json', SCOPES)
creds = tools.run_flow(flow, store)
and your store will be populated with a new token that can be used for uploading.
You say you "just get the Oauth2.0_token response(a JSON format with access_token, refresh_token...)" and "put this token string with "Bearer " into request headers".
Unfortunately documentation on this isn't super clear in a lot of places. What you are supposed to provide after "Bearer" is the "access_token" field only, not the entire JSON string with all the token fields in it. For reference, this is a single string of random looking characters which probably starts with "ya29." and is pretty long - in my case it's 170 characters.
I'm developping a Rest API, MyApi.
In there, I'm using Feign (and swagger codegen) to generate a client for another API, let's call it Ext-API.
The user will have called Ext-API previously and among other things will have retrieved a JWT Token.
He'll then call my API using Basic Auth and in the body it'll give me the JWT token.
I'm to use this JWT token as auth header to connect to Ext-API from my API and do some more stuff on behalf of the user.
However all example of Oauth & Feign example rely on the Oauth also being used to connect to the API using the generated client.
I can't find how I could, on every request, update the Oauth Token.
There are nothing exposed by feign to do this.
Atm I'm using regular Rest template.
You can used #RequestHeader in feign Client, see below
#FeignClient(name = "<name>", configuration = <configclass>)
public interface Client {
public final String AUTH_TOKEN = "Authorization";
#RequestMapping(method = RequestMethod.GET, value = "users", produces = "application/json")
public HttpEntity<List<User>> getUsers(#RequestHeader(AUTH_TOKEN) String oruToken,
#RequestParam("<param>") Integer value);
}
and from you program you can pass token to feign client
I have a use-case where I need to spoof a white-listed Redirect URL locally when performing OAuth 2 authentication.
I'm running a very basic web-server coupled with a hosts file entry for the domain I'm spoofing. I'm able to correctly negotiate my tokens and return them to Paw, but Paw isn't picking up my access_token or refresh_token, it simply displays the raw response:
Here's my server code (with placeholders for sensitive data):
var http = require('http'),
request = require('request');
var PORT = 6109;
var server = http.createServer(function(req, res) {
var code = req.url.split('?')[1].split('=')[2];
request({
url: 'https://<access token URL>/oauth2/token?code=' + code,
method: 'POST',
form: {
'client_id': <client_id>,
'client_secret': <client_secret>,
'grant_type': 'authorization_code',
'redirect_uri': <spoofed redirect URL>
}
}, function(err, response, data) {
data = JSON.parse(data);
res.writeHead(200, {'Content-Type': 'application/json'});
res.write(JSON.stringify(data.result));
// I also tried this with the same end-result
// res.writeHead(200);
// res.write('access_token=' + data.result.access_token + '&token_type=' + data.result.token_type + '&refresh_token=' + data.result.refresh_token);
res.end();
});
});
server.listen(PORT, function() {
console.log('Server listening on port %d', PORT);
});
What am I missing? Why isn't Paw finding my tokens?
Here's my configuration for reference:
Some other noteworthy points:
The OAuth provider is non-standard and flubs quite a few things from the spec (my proxy exists in part to patch up the non-standard bits)
The domain for the Redirect URL is real, but the URL does not resolve (this is a part of the reason for the local hosts entry)
I'm not showing this part of the flow, but I am correctly completing the authorization step prior to being given the code value
I think you're probably confused between the Authorization URL and Access Token URL. When you're in Authorization Code grant type for OAuth 2, you're expected to have a user confirmation step in a web page (the Authorization URL).
Which makes me guess that instead, you're expecting instead to use the Password Grant or Client Credentials? Otherwise, if you want to use Authorization URL, you'll need to specify a webpage at the Authorization URL.
Note: I've tried your Node.js script in Paw using the two last grants I mentioned (Password Grant & Client Credentials), and it works nicely.
Update: Following the comments below, I understand more what you are doing. The Authorization Request should (if successful) return a 302 redirect response to the Redirect URL page, and append a code URL query param to it. It seems like you're returning a JSON response with the code instead, so Paw isn't catching it.
According to the OAuth 2.0 spec (RFC 6749), section *4.1.2. Authorization Response*, if granted, the code should be passed as a URL query param (i.e. a ?key=value param in the URL) to the Redirect URL when doing the redirection.
If the resource owner grants the access request, the authorization
server issues an authorization code and delivers it to the client by
adding the following parameters to the query component of the
redirection URI using the "application/x-www-form-urlencoded" format
Quoting the example from the spec, here's how the response of the Authorization Request should look like if it's a success (code is granted):
HTTP/1.1 302 Found
Location: https://client.example.com/cb?code=SplxlOBeZQQYbYS6WxSbIA
&state=xyz
I saw that the Redirect URL contains "my Spoofed Uri".
When we need to use authorization code flow, we provide the authorization code and redirect Uri.
When the URI you are providing does not match the URI saved for the client in Identity server, you will not be able to get the token as the URI does not match with the client authorization code.
For example : Consider client identity in the Identity server be:
Auth Code: "xyx"
Redirect Uri: "www.mylocalhost.com\xyz"
And in your example the combination you are providing is:
Auth Code: "xyx"
Redirect Uri: "<my spoofed uri>"
As these 2 wont match there will be no token received.
I believe if you use the correct URI that is registered with the client in the Identity server, you will be able to receive the token.
I've a problem when trying to do a webrequest to UGC and authenticate using oAuth. I'm making a webrequest such as:-
WebRequest wr = WebRequest.Create("http://ugc.service/odata.svc/Ratings(Id=200)");
wr.Headers["authorization"] = "OAuth " + auth;
Where auth is my token returned from the access_token.svc. According to the documentation the token returned from the service should be something like:-
HufXeuUt%2FYYElA8SYjJOkUkrXxV9dyXRirmKhjW%2Fb%2FU%3D
However, what I'm being returned from access_token.svc is more like:-
{"access_token":"client_id%3dtestuser%26expiresOn%3d1361898714646%26digest%3d%2fW%2fvyhQneZHrm1aGhwOlgLtA9xGWd77hkxWbjmindtM%3d","expires_in":300}
I've parsed the JSON to extract various strings and attempted to pass these through to the authorization but whatever I try I get an error in the logs - "ERROR OAuth2AccessToken - Digest is wrong." Exactly what part of the token and in what format should I be passing through to authorization?
Many thanks
John
Like you mentioned, the protocol is this:
You make a post request to the access token end-point to get a token (you need to provide here your client_id and your client_secret as headers or as query parameters);
You get an answer similar to this: {"access_token":"sometoken","expires_in":300};
2.1 Worth knowing is that the token is url encoded and in UTF-8 format so, on Java side you need to do URLDecoder.decode("sometoken", "UTF-8"); while on .NET side you need to do HttpUtility.UrlDecode("sometoken", System.Text.Encoding.UTF8);;
Your next request needs to include the authorization header. On Java side you do builder.header("authorization", "OAuth " + decodedTokenString); while on .NET side you can use Client.Headers["authorization"] = "OAuth " + DecodedTokenString;
Worth mentioning is that the SharedSecret defined in the cd_webservice_conf.xml (/Configuration/AuthenticationServer/SharedSecret/) of the TokenAccessPoint needs to be the same as the SharedSecret defined in the cd_ambient_conf.xml (/Configuration/Security/SharedSecret/) of the (WebService)EndPoint.
Are you sure you decoded properly the token gotten from the server? Are you sure that you configured the proper SharedSecret in the two configuration files?
Hope this helps.