I'm trying to authenticate in Vimeo using Scribe. It's not going over too well. I keep getting error code 100 back, but it still gives me an Authorization URL and when I go to it I'm able to grant access. It's just when I enter the authorization code in and try to trade the request token for an access token it doesn't work. I'm using the Facebook example and tweaking it to work with Vimeo. I don't really know what I'm doing here. I asked a question earlier and was told that I need to include apache commons codec on my classpath. Well, I included it in my environment variables and that didn't change anything. So I just added it to my libraries for the project and that seemed to get me a step farther. Now I just have no idea what to do from here. I don't understand why I'm getting this. Here's my code and output:
public class VimeoTest
{
private static final String NETWORK_NAME = "Vimeo";
private static final Token EMPTY_TOKEN = null;
public static void main(String[] args)
{
// Replace these with your own api key and secret
String apiKey = "MYAPIKEY";
String apiSecret = "MYAPISECRET";
OAuthService service = new ServiceBuilder()
.provider(VimeoApi.class)
.apiKey(apiKey)
.apiSecret(apiSecret)
.debug()
.build();
Scanner in = new Scanner(System.in);
System.out.println("=== " + NETWORK_NAME + "'s OAuth Workflow ===");
System.out.println();
OAuthRequest orequest = new OAuthRequest(Verb.GET, "http://vimeo.com/api/rest/v2");
orequest.addQuerystringParameter("method", "vimeo.test.null");
Response send = orequest.send();
System.out.println(send.getBody());
// Obtain the Authorization URL
System.out.println("Fetching the Authorization URL...");
Token requestToken = service.getRequestToken();
String authorizationUrl = service.getAuthorizationUrl(requestToken);
System.out.println("Got the Authorization URL!");
System.out.println("Now go and authorize Scribe here:");
//I do NOT want to have to do this. Is there any other way I can have this authorize without going to a web browser to do this?
System.out.println(authorizationUrl);
System.out.println("And paste the authorization code here");
System.out.print(">>");
Verifier verifier = new Verifier(in.nextLine());
System.out.println();
// Trade the Request Token and Verfier for the Access Token
System.out.println("Trading the Request Token for an Access Token...");
Token accessToken = service.getAccessToken(EMPTY_TOKEN, verifier);
//****Breaks on the line above.****
//I think it's because the orequest.send() returned a 100 error code
//Note, EMPTY_TOKEN is declared as null, but I think that's ok. Verifier is not null.
System.out.println("Got the Access Token!");
System.out.println("(if your curious it looks like this: " + accessToken + " )");
System.out.println();
Here's the output:
=== Vimeo's OAuth Workflow ===
1.0
<?xml version="1.0" encoding="utf-8"?>
<rsp generated_in="0.0033" stat="fail">
<err code="100" expl="The API key passed was not valid" msg="Invalid API Key" />
</rsp>
Fetching the Authorization URL...
obtaining request token from http://vimeo.com/oauth/request_token
setting oauth_callback to oob
generating signature...
base string is: POST&http%3A%2F%2Fvimeo.com%2Foauth%2Frequest_token&oauth_callback%3Doob%26oauth_consumer_key%3DACONSUMERKEY%26oauth_nonce%3D2861480766%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1331941401%26oauth_version%3D1.0
signature is: 7H/C4F4rK0FYZ5oZGf76Rl8P8yQ=
appended additional OAuth parameters: { oauth_callback -> oob , oauth_signature -> 7H/C4F4rK0FYZ5oZGf76Rl8P8yQ= , oauth_version -> 1.0 , oauth_nonce -> 2861480766 , oauth_signature_method -> HMAC-SHA1 , oauth_consumer_key -> ACONSUMERKEY , oauth_timestamp -> 1331941401 }
using Http Header signature
sending request...
response status code: 200
response body: oauth_token=bf3da4ec799559c9f8b1f8bda2b8d6ee&oauth_token_secret=AOAUTHTOEKN SECRET&oauth_callback_confirmed=true
Got the Authorization URL!
Now go and authorize Scribe here:
http://vimeo.com/oauth/authorize?oauth_token=bf3da4ec799559c9f8b1f8bda2b8d6ee
And paste the authorization code here
>>unicorn-duqx0
Exception in thread "main" java.lang.NullPointerException
Trading the Request Token for an Access Token...
obtaining access token from http://vimeo.com/oauth/access_token
at org.scribe.oauth.OAuth10aServiceImpl.getAccessToken(OAuth10aServiceImpl.java:75)
at autouploadermodel.VimeoTest.main(VimeoTest.java:51)
Java Result: 1
BUILD SUCCESSFUL (total time: 27 seconds)
Edit: added .debug() to new ServiceBuilder() and updated the output accordingly.
Change this line:
Token accessToken = service.getAccessToken(EMPTY_TOKEN, verifier);
For:
Token accessToken = service.getAccessToken(requestToken, verifier);
Edit
The whole key unauthorized part is because this piece of code:
OAuthRequest orequest = new OAuthRequest(Verb.GET, "http://vimeo.com/api/rest/v2");
orequest.addQuerystringParameter("method", "vimeo.test.null");
Response send = orequest.send();
System.out.println(send.getBody());
You're trying to make a GET request to the api root (not sure even if this is a valid resource) without signing it. Of course it's going to yield an unauthorized error.
Related
I need to create tests using RestAssured - Java for testing REST API. In order to get an authentication token (OAuth 2.0), I need to send from postman request filled as in the screen below. However, in java tests, I can not use postman. Any idea how it should look like java code to get authentication token?
Below is an algorithm/snippet of how your code should look like:
Prerequisites:
Initial OAuth token and clientID should be taken and stored (in a DB or any data
storage).
Time of OAuth token generation must be stored
Refresh token must be stored.
Validity (For how long the current OAuth token is valid) of OAuth token must be known/stored.
Algorithm:
long validityOfOAuthToken = DB.get ("validityOfOAuthToken");
long OAuthGeneratedTimeInMillis = DB.get ("oAuthGeneratedTime");
long currentTimeInMillis = DateTime.now (DateTimeZone.UTC).getMillis ( );
if (currentTimeInMillis - OAuthGeneratedTimeInMillis > validityOfOAuthToken)
{
String clientID = DB.get ("clientID");
String refreshToken = DB.get ("refreshToken");
String accessToken = generateAccessToken (clientID, refreshToken); // API Invocation to get access token via refresh token
DB.save ("oauthToken", accessToken);
DB.save ("oAuthGeneratedTime", DateTime.now (DateTimeZone.UTC).getMillis ( ));
return accessToken;
}
else
{
return DB.get ("oauthToken");
}
Do note/store clientid and secret that you get from uaa server:
Then First try to call uaa for tokens :
Response response =
given()
.header("Authorization",<client id>:<client secret>)
.contentType("application/x-www-form-urlencoded")
.formParam("grant_type","authorization_code") .formParam("redirect_uri",REDIRECT_URL)
.formParam("response_type","code")
.formParam("code", AUTHORIZATION_CODE)
.formParam("client_id", CLIENT_ID)
.formParam("client_secret", CLIENT_SECRET)
.when()
.post(BASE_URI+"/oauth2/token");
Then Fetch out information of access token and token type like below:
JSONObject jsonObject = new JSONObject(response.getBody().asString());
String accessToken = jsonObject.get("access_token").toString();
String tokenType = jsonObject.get("token_type").toString();
log.info("Oauth Token with type " + tokenType + " " + accessToken);
Lastly call your endpoint by passing access token in header:
Response response =
given()
.headers(
"Authorization",
"Bearer " + accessToken,
"Content-Type",
ContentType.JSON,
"Accept",
ContentType.JSON)
.when()
.get(url)
.then()
.contentType(ContentType.JSON)
.extract()
.response();
Please try this .
Using "client_secret" and "client_id" it creates a bearerToken and later we can use it to authenticate.
RestAssured.baseURI = "http://coop.apps.symfonycasts.com/";
RestAssured.basePath = "/token";
// client_secret is different from oauth2 token
Response response = given()
.formParam("client_id","samapp")
.formParam("client_secret","f56f459193cee56817c2a99c205654b7")
.formParam("grant_type", "client_credentials").post("");
//To get token
String bearerToken = response.jsonPath().get("access_token");
System.out.println("The bearer token value is "+bearerToken);
Assert.assertEquals(200, response.getStatusCode(),"Status code mismatches");
This should work -
public class AuthenticationUtils {
public static String generateOAuth2Token() {
return "Bearer "+RestAssured.given().auth().basic("{YOUR_USERNAME}", "{YOUR_PASSWORD}")
.formParam("client_id", "{YOUR_CLIENT_ID}")
.formParam("client_secret", "{YOUR_SECRET}")
.formParam("grant_type", "client_credentials")
.formParam("{ANY_OTHER_TOKEN_NAME}", "{TOKEN_VALUE}")
.formParam("redirect_uri", "{http://take-me-here-next.com/api/endpoint}")
.when().post("https://{YOUR_TOKEN_URL}/oauth2/v2.0/token")
.then()
.extract().path("access_token");
}
}
substitute values within {} with your's
Grant type in question posted is Authrization code but everyone replied for client credential
I have recently started playing with the Bing Ads api for managing my ads and campaigns and I am having problem in authenticating user (not oauth authentication).
I authenticated my user using oauth by the following
private String devToken = "ZZZZZ";
private String clientId = "AAA0BBB-XXXX-AAAAA";
protected static String UserName = "a.v#h.c";
protected static String Password = "********";
// To get the initial access and refresh tokens you must call requestAccessAndRefreshTokens with the authorization redirection URL.
OAuthTokens tokens = oAuthDesktopMobileAuthCodeGrant.requestAccessAndRefreshTokens(url);
System.out.println("Access token: " + tokens.getAccessToken());
System.out.println("Refresh token: " + tokens.getRefreshToken());
authorizationData = new AuthorizationData();
authorizationData.setDeveloperToken(getDevToken());
authorizationData.setAuthentication(oAuthDesktopMobileAuthCodeGrant);
This authenticates my user just fine since I can use the ICustomerManagementService.class just fine for accounts related information
customerServiceClient = new ServiceClient<>(authorizationData, ICustomerManagementService.class);
ArrayOfAccount accounts = searchAccountsByUserId(user.getId());
The above works perfectly. But when I try to do the same with ICampaignManagementService.class like below
campaignServiceClient = new ServiceClient<>(authorizationData, ICampaignManagementService.class);
GetAdsByAdGroupIdRequest cReq = new GetAdsByAdGroupIdRequest();
cReq.setAdGroupId(1234567890L);
campaignServiceClient.getService().getAdsByAdGroupId(cReq);
I get error code 106 saying that the user is not authorized.
The user does not represent a authorized developer.
106
Any help in this regard ?
Please try to set the CustomerId and CustomerAccountId header elements (CustomerId and AccountId of AuthorizationData). These headers are not available with the Customer Management service, but are applicable for Campaign Management service. If that does not resolve the issue please feel free to send the SOAP request + response to support for investigation. I hope this helps!
I am making use of the Android Async Http Library in my app to make async http requests.
I have come into a situation in my android app where the following happens. My web api makes use of an access token and a refresh token. On every request that I make I check if the access token is still valid. If it is not I then issue a http post to go get a new access token using the refresh token.
Now i have noticed the following situation.
user of my app leaves their phone inactive for enough time for the access token to expire. When they wake the phone up. In my onResume() function I fire off two separate http requests.
Request 1 checks the access token and determines its not valid. it then issues a refreshAccessToken request.
While Request 1 is waiting for the response, Request 2 also checks the access token and determines its not valid. And it also issues a refreshAccessToken request.
Request 1 returns successfully and updates the access token and refresh token values.
Request 2, then gets a 401 response from the api as the refresh token which it provided has already been used. My application then thinks that there is an error with the refreshToken and logs the user out.
This is obviously incorrect and I would like to avoid it. I have in the mean time, done a double check in the refreshAccessToken onFailed() method. To see if the accessToken is maybe valid again. However this is inefficient as I am still sedning two requests over the air, and my API has to handle the failed refresh attempt.
Question:
Now my issue is that i cant use any locks or synchronization as you cannot block the main UI thread in android. And Android Async Http Library handles all of the different threads etc.
Request 2 also checks the access token and determines its not valid.
This is wrong. Since Request 1 may have already issued refreshAccessToken request, then the state of the access token cannot be determined by consulting the server.
So you need a combined operation getAccessToken() which checks access token, issues refreshAccessToken when needed, and, when called in parallel, only waits for previously called getAccessToken() operation.
UPDATE. refreshAccessToken is a part of a class which serves as a gatekeeper and allows requests to run only if access token is refreshed. If token is not refreshed, gatekeeper sends single request to refresh the token. Meantime, input requests are saved in a queue. When the token is refreshed, the gatekeeper lets saved requests to run.
I found the solution with authenticator, the id is the number of the request, only for identification. Comments are in Spanish
private final static Lock locks = new ReentrantLock();
httpClient.authenticator(new Authenticator() {
#Override
public Request authenticate(#NonNull Route route,#NonNull Response response) throws IOException {
Log.e("Error" , "Se encontro un 401 no autorizado y soy el numero : " + id);
//Obteniendo token de DB
SharedPreferences prefs = mContext.getSharedPreferences(
BuildConfig.APPLICATION_ID, Context.MODE_PRIVATE);
String token_db = prefs.getString("refresh_token","");
//Comparando tokens
if(mToken.getRefreshToken().equals(token_db)){
locks.lock();
try{
//Obteniendo token de DB
prefs = mContext.getSharedPreferences(
BuildConfig.APPLICATION_ID, Context.MODE_PRIVATE);
String token_db2 = prefs.getString("refresh_token","");
//Comparando tokens
if(mToken.getRefreshToken().equals(token_db2)){
//Refresh token
APIClient tokenClient = createService(APIClient.class);
Call<AccessToken> call = tokenClient.getRefreshAccessToken(API_OAUTH_CLIENTID,API_OAUTH_CLIENTSECRET, "refresh_token", mToken.getRefreshToken());
retrofit2.Response<AccessToken> res = call.execute();
AccessToken newToken = res.body();
// do we have an access token to refresh?
if(newToken!=null && res.isSuccessful()){
String refreshToken = newToken.getRefreshToken();
Log.e("Entra", "Token actualizado y soy el numero : " + id + " : " + refreshToken);
prefs = mContext.getSharedPreferences(BuildConfig.APPLICATION_ID, Context.MODE_PRIVATE);
prefs.edit().putBoolean("log_in", true).apply();
prefs.edit().putString("access_token", newToken.getAccessToken()).apply();
prefs.edit().putString("refresh_token", refreshToken).apply();
prefs.edit().putString("token_type", newToken.getTokenType()).apply();
locks.unlock();
return response.request().newBuilder()
.header("Authorization", newToken.getTokenType() + " " + newToken.getAccessToken())
.build();
}else{
//Dirigir a login
Log.e("redirigir", "DIRIGIENDO LOGOUT");
locks.unlock();
return null;
}
}else{
//Ya se actualizo tokens
Log.e("Entra", "El token se actualizo anteriormente, y soy el no : " + id );
prefs = mContext.getSharedPreferences(BuildConfig.APPLICATION_ID, Context.MODE_PRIVATE);
String type = prefs.getString("token_type","");
String access = prefs.getString("access_token","");
locks.unlock();
return response.request().newBuilder()
.header("Authorization", type + " " + access)
.build();
}
}catch (Exception e){
locks.unlock();
e.printStackTrace();
return null;
}
}
return null;
}
});
Earlier i was using GET search/tweets of Twitter API 1.0 To get tweets according to #tags in Grails
Map jsonMap = grails.converters.JSON.parse(new URL('http://search.twitter.com/search.json?q=%23' + URLEncoder.encode(tag) + '&offset=' + offset + 'result_type=mixed&lang=en&page=' + page).text)
But due to change in Twitter API version 1.1 now the above call requires Authentication.
I want to fetch tweets on behalf of Application(Authentication) not by user Authentication.
Is this possible?
I came across application-only-auth but unable to implement it.
https://dev.twitter.com/docs/auth/application-only-auth
How to implement above using scribe API in Grails.
I have done like this and it worked for me.
OAuthService service = new ServiceBuilder().provider(TwitterApi.class).apiKey(grailsApplication.config.oauth.providers.twitter.key).apiSecret(grailsApplication.config.oauth.providers.twitter.secret).build()
OAuthRequest request = new OAuthRequest(Verb.GET, 'https://api.twitter.com/1.1/search/tweets.json?q=%23' + URLEncoder.encode(tag) + '&count=100&result_type=mixed&lang=en');
Token accessToken = new Token(grailsApplication.config.oauth.providers.twitter.accessToken, grailsApplication.config.oauth.providers.twitter.accessSecret)
service.signRequest(accessToken, request);
Response response = request.send();
JSONElement jsonMap = grails.converters.JSON.parse(response.getBody());
I get the error
com.google.gdata.util.AuthenticationException: Unknown authorization header
at com.google.gdata.client.http.HttpGDataRequest.handleErrorResponse(HttpGDataRequest.java:600) ~[gdata-core-1.0.jar:na]
at com.google.gdata.client.http.GoogleGDataRequest.handleErrorResponse(GoogleGDataRequest.java:563) ~[gdata-core-1.0.jar:na]
at com.google.gdata.client.http.HttpGDataRequest.checkResponse(HttpGDataRequest.java:552) ~[gdata-core-1.0.jar:na]
at com.google.gdata.client.http.HttpGDataRequest.execute(HttpGDataRequest.java:530) ~[gdata-core-1.0.jar:na]
at com.google.gdata.client.http.GoogleGDataRequest.execute(GoogleGDataRequest.java:535) ~[gdata-core-1.0.jar:na]
when trying to access the Google Calendar data via their API.
Here is what happens before that error.
1) I authenticate with Google:
final AccessTokenResponse response =
new GoogleAuthorizationCodeGrant(httpTransport,
jsonFactory,
clientId, clientSecret, authorizationCode,
redirectUrl).execute();
final GoogleAccessProtectedResource accessProtectedResource =
new GoogleAccessProtectedResource(
response.accessToken, httpTransport, jsonFactory,
clientId, clientSecret,
response.refreshToken);
LOGGER.debug("response.accessToken: {}", response.accessToken);
this.oauthAccessToken = response.accessToken;
...
2) I read some data via the tasks API:
this.service =
new Tasks(httpTransport, accessProtectedResource,
jsonFactory);
this.service.setApplicationName(this.applicationName);
This seems to work.
3) Then I try to read data from the Google Calendar API:
final OAuthHmacSha1Signer signer = new OAuthHmacSha1Signer();
final GoogleOAuthParameters oauth = new GoogleOAuthParameters ();
oauth.setOAuthConsumerKey("myapp.com");
oauth.setOAuthConsumerSecret(CLIENT_SECRET); // Client secret from "Google API access" page, "Client secret" entry
oauth.setOAuthToken(this.oauthAccessToken); // Access token from step 1
oauth.setOAuthTokenSecret(aAuthorizationCode);
// aAuthorizationCode is taken from the callback URL.
// For http://myapp.com/oauth2callback?code=4/uy8Arb4bhRPwWYSr3QwKPt9lIZkt
// aAuthorizationCode is equal to "4/uy8Arb4bhRPwWYSr3QwKPt9lIZkt" (without quotes)
oauth.setScope(SCOPE_CALENDAR); // https://www.google.com/calendar/feeds/
final CalendarService calendarService =
new CalendarService(APPLICATION_NAME);
calendarService
.setOAuthCredentials(oauth, signer);
LOGGER.debug("calendarService: {}", calendarService);
final URL feedUrl =
new URL(
"http://www.google.com/calendar/feeds/default/allcalendars/full");
final CalendarFeed resultFeed =
calendarService.getFeed(feedUrl, CalendarFeed.class);
At the last line (calendarService.getFeed...) the aforementioned exception occurs.
I have following questions:
1) Is my call
oauth.setOAuthConsumerKey
correct?
I. e. is the "consumer key" equal to "Product name" in the Google API console, or to "Client ID" field (value is something like 42912397129473.apps.googleusercontent.com)
2) Is the setOAuthTokenSecret correct? I. e. is it the code that I get, when Google redirects the user back to my app?
3) If questions 2 and 3 were answered with yes, what else can be the cause of my problem?
Thanks
Dmitri
P. S.: Previously, I could access Google calendar with simple access (i. e. with Google user name and password). However, this is not an option now because users of my app will not want to give away their Google password.
Finally, I solved my problem by following the example at
http://code.google.com/p/gdata-java-client/source/browse/trunk/java/sample/oauth/OAuthExample.java
My advice to all future victims^W users of OAuth: Pay attention to the smallest details in the OAuth tutorials. The OAuth devil lies in details.