feedback about FreshBooks API for data synchronization needs

880 views
Skip to first unread message

Raimonds Simanovskis

unread,
Aug 13, 2012, 1:45:44 PM8/13/12
to freshbo...@googlegroups.com
I just finished eazyBI reporting application integration with FreshBooks (https://eazybi.com/help/freshbooks) and wanted to share some issues and improvement ideas regarding FreshBooks API when used for data synchronization from FreshBooks to external application.

- It is strange that project.list (http://developers.freshbooks.com/docs/projects/#project.list) does not allow to get archived and deleted projects (it does not accept folder parameter). When importing historical time reporting data then most probably some or many projects are already archived and therefore it would be good to be able to get list of archived projects.

- As I understand in staff.list (http://developers.freshbooks.com/docs/staff/#staff.list) results there is no difference between staff members and contractors - it would be good to have additional type field which would identify if this person is staff member or contractor.

- As I understand if invoice line is generated from time entries or expenses then such lines are always grouped by project (meaning one line could come just from one project). Currently to identify corresponding project_id for invoice line it is necessary to look up time entry using time_entry_id or look up expense using expense_id. It would be better if in invoice.list (http://developers.freshbooks.com/docs/invoices/#invoice.list) invoice lines already would have invoice_id field for time and expense lines.

- Now it is not very efficient to synchronize all time entries using time_entry.list (http://developers.freshbooks.com/docs/time-entries/#time_entry.list). There are just date_from and date_to parameters available but sometimes some user has entered or corrected very old time entries. Therefore currently I am requesting all time entries for all projects during data synchronization to ensure that all time entries are up to date.
One improvement could be to have updated_from parameter as in case of invoice.list to get just just recently entered time entries. But then the issue is that there is no way how to get information about recently deleted time entries (as there is no deleted folder for time entries).
Other option could be to have some special project date field which is updated when time entries are either created, updated or deleted for that project. Then during regular data synchronization time entries could be synchronized just for projects which have recent time entry changes.
Are there any other suggestions how to do regular time entry synchronization without full data import?

- I already mentioned issue with category.list request which does not return default expense categories - as I understand it hopefully will be fixed.

I will appreciate any comments regarding these mentioned issues and improvement ideas.

And if anyone is interested in more advanced FreshBooks time, expenses and invoices reporting then please try out eazyBI :) (https://eazybi.com/help/freshbooks)

Kind regards,
Raimonds

Eric Lannert

unread,
Jan 16, 2013, 6:10:21 PM1/16/13
to freshbo...@googlegroups.com
i'm not seeing any contractors in staff.list.

does anyone know of a way to get them? i need their id numbers for linking their time entries with other systems.

Anton Nguyen

unread,
Jan 17, 2013, 6:00:44 PM1/17/13
to freshbo...@googlegroups.com
Hey Eric,

We have a contractor.list call that you can use.

Let me know if that helps!
Anton

Arpit Garg

unread,
May 13, 2013, 3:18:30 PM5/13/13
to freshbo...@googlegroups.com
i am trying to get list of staff from freshbooks, but any api i use i get authorization error. I am sure i am doing something wrong, but there is hardly any java example available on how to use Oauth in freshbooks in java.
can you let me know what i am doing wrong in code below
all i get is authorization failed 20010 error

HttpPost request = new HttpPost( "https://login-accounts.freshbooks.com/api/2.1/xml-in" );
StringEntity se = new StringEntity("<request method=\"staff.list\"></request>","UTF-8");
se.setContentType("text/xml");
request.addHeader( "Authorization", "Basic OAuthSecretkey" );
request.addHeader("Content-Type","application/x-www-form-urlencoded");
request.setEntity(se);
// View response
System.out.println("RESPONSE START");
HttpClient client = new DefaultHttpClient();
HttpResponse response = client.execute(request);

HttpEntity entity = response.getEntity();
 
String inputLine ;
BufferedReader in = new BufferedReader(new InputStreamReader(entity.getContent()));
try {
while ((inputLine = in.readLine()) != null) {
System.out.println(inputLine);
}
in.close();
} catch (IOException e) {
e.printStackTrace();
}
System.out.println("RESPONSE END");

Anton Nguyen

unread,
May 14, 2013, 10:57:10 AM5/14/13
to freshbo...@googlegroups.com
Hey Arpit,

We're using OAuth 1.0a, so following the spec should be work with Java as well. That being said, from what I'm seeing, it looks like you're using Basic Token Authorization, but you're giving the OAuth Secret Key. 

With Basic Token Authorization, you're given an API Token in My Account > FreshBooks API and its on the "Authentication Token" section. With that Token, you take a string of the form "AuthenticationToken:X" and then you base64-encode it. That encoded string is what you pass in as the Authorization header:

request.addHeader( "Authorization", "Basic Base64EncodedString" ); 

With OAuth, assuming you've completed the OAuth dance, here's an example of what the Authorization would look like:
request.addHeader("Authorization",  'OAuth realm="",oauth_version="1.0",oauth_consumer_key="<consumerkey>",oauth_timestamp="1368543131",oauth_nonce="qztiuqHbnMHS92N",oauth_signature_method="PLAINTEXT",oauth_signature="<consumersecret>%2526<accesstokensecret>",oauth_token="<accesstoken>"');

If you're not familiar with the OAuth dance, or how to get access tokens, nonces, timestimes, etc... let me know and I'll walk you through the entire process. :)

Anton

Arpit Garg

unread,
May 15, 2013, 7:27:23 AM5/15/13
to freshbo...@googlegroups.com
hello Anton,
firstly many thanks for detailed response and yes, if you could help me with more details about oauth dance and others in Java then it will be extremely helpful to me
things like "then you base64-encode it? how to do this - syntax with command in java?
and how to get access tokens, nonces, timestimes - again sample in java
"<consumersecret>%2526<accesstokensecret>",oauth_token="<accesstoken>
what is consumersecret and what is accesstokensecret? as all i can see in MY ACCOUNT in freshbooks is OauthToken and Oauth Secret not comsumer secret key and accesstokensecret

I am sorry for asking basics, but i would need a sample java code for above and once that is available i will do the needful on my end.
THanks once again.

- arpit

Anton Nguyen

unread,
May 15, 2013, 12:16:59 PM5/15/13
to freshbo...@googlegroups.com
Hey Arpit,

To be honest, I haven't touched java code in years, but I can talk to some of the other devs here, and see if they can help.

To base64-encode with Java, I found this on stackoverflow that might help: http://stackoverflow.com/questions/13109588/base64-encoding-in-java

Also, in your account, that's not the OAuth token you see. Its the token for Basic Authentication, not OAuth Authentication.

As for the OAuth Dance, I wrote up a quick walkthrough of the entire process: https://gist.github.com/AntonNguyen/5583949

Lemme know if it makes sense!
Anton

Arpit Garg

unread,
May 15, 2013, 1:04:12 PM5/15/13
to freshbo...@googlegroups.com
hello Anton,
thanks a lot for inputs. yes if some other dev can help me with java example, it will be quick for me, but i am going through all you have shared and hopefully things will turn good. And if other dev have some java example, it will be helpful.

thanks,
arpit

Barum Rho

unread,
May 15, 2013, 2:41:30 PM5/15/13
to freshbo...@googlegroups.com
Hi Arpit, it's usually easier to use a library for doing OAuth.
Please take a look at this library for example: https://code.google.com/p/oauth-signpost/
Also, if you are working on a program just for yourself, it might be easier to use simple token authentication.

Michael Cole

unread,
May 15, 2013, 4:29:49 PM5/15/13
to freshbo...@googlegroups.com
To re-hijack this thread, I'm going to run into the first two problem Raimonds Simanovskis pointed out.

Any work-arounds?

Mike

Arpit Garg

unread,
May 16, 2013, 8:20:48 AM5/16/13
to freshbo...@googlegroups.com
hello Barum,
I have tried, but now i am getting bad request (404) from service provider.
I am using signpost jar and code as below

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import oauth.signpost.OAuth;
import oauth.signpost.OAuthConsumer;
import oauth.signpost.OAuthProvider;
import oauth.signpost.basic.DefaultOAuthConsumer;
import oauth.signpost.basic.DefaultOAuthProvider;
final String CONSUMER_KEY = "my-accounts";
final String CONSUMER_SECRET = "OAuth Secret key" ; //(i just copy+paste from fresbooks Myaccounts)
final String APPLICATION_NAME = "signpost-test";
final String freshbooks_REQUEST_TOKEN_URL = "https://my-accounts.freshbooks.com/oauth/oauth_request.php";
    final String freshbooks_ACCESS_TOKEN_URL = "https://my-accounts.freshbooks.com/oauth/oauth_authorize.php?oauth_token=";
    final String freshbooks_AUTHORIZE_URL = "https://my-accounts.freshbooks.com/oauth/oauth_access.php";
   
     OAuthConsumer consumer = new DefaultOAuthConsumer(CONSUMER_KEY, CONSUMER_SECRET);

        OAuthProvider provider = new DefaultOAuthProvider(freshbooks_REQUEST_TOKEN_URL,
            freshbooks_ACCESS_TOKEN_URL, freshbooks_AUTHORIZE_URL);

        System.out.println("Fetching request token from freshbooks...");

        // we do not support callbacks, thus pass OOB
        String authUrl = provider.retrieveRequestToken(consumer, OAuth.OUT_OF_BAND);
        authUrl = OAuth.addQueryParameters(authUrl, OAuth.OAUTH_CONSUMER_KEY, CONSUMER_KEY,
            "application_name", APPLICATION_NAME);
        System.out.println("Request token: " + consumer.getToken());
        System.out.println("Token secret: " + consumer.getTokenSecret());


Any help will be appreciated..

Anton Nguyen

unread,
May 16, 2013, 10:46:55 AM5/16/13
to freshbo...@googlegroups.com
Hey Arpit,

What line were you receiving the error on? 404 means a page was not found. I took at look at your URLs and they're all valid. One problem I can see, is ACCESS_TOKEN_URL and AUTHORIZE_URL being mixed up. 

Anton

Arpit Garg

unread,
May 16, 2013, 11:11:33 AM5/16/13
to freshbo...@googlegroups.com
I tried interchanging access and authorize url, but still not able to get through. I get error as below after system.out.println()


  System.out.println("Fetching request token from freshbooks...");
// we do not support callbacks, thus pass OOB
        String authUrl = provider.retrieveRequestToken(
consumer, OAuth.OUT_OF_BAND);
        authUrl = OAuth.addQueryParameters(authUrl, OAuth.OAUTH_CONSUMER_KEY, CONSUMER_KEY,
            "application_name", APPLICATION_NAME);

error log...is below -
----------------------------

Fetching request token from freshbooks...
Exception in component tJava_1
oauth.signpost.exception.OAuthCommunicationException: Communication with the service provider failed: Service provider responded in error: 400 (Bad Request)
    at oauth.signpost.AbstractOAuthProvider.retrieveToken(AbstractOAuthProvider.java:218)
    at oauth.signpost.AbstractOAuthProvider.retrieveRequestToken(AbstractOAuthProvider.java:74)
    at talenddemo.t_0_1.t.tJava_1Process(t.java:776)
    at talenddemo.t_0_1.t.tLibraryLoad_4Process(t.java:712)
    at talenddemo.t_0_1.t.tLibraryLoad_3Process(t.java:602)
    at talenddemo.t_0_1.t.tLibraryLoad_2Process(t.java:514)
    at talenddemo.t_0_1.t.tLibraryLoad_1Process(t.java:426)
    at talenddemo.t_0_1.t.runJobInTOS(t.java:1001)
    at talenddemo.t_0_1.t.main(t.java:869)
Caused by: oauth.signpost.exception.OAuthCommunicationException: Service provider responded in error: 400 (Bad Request)
    at oauth.signpost.AbstractOAuthProvider.handleUnexpectedResponse(AbstractOAuthProvider.java:245)
    at oauth.signpost.AbstractOAuthProvider.retrieveToken(AbstractOAuthProvider.java:193)
    ... 8 more

itDuzzit Steve

unread,
May 16, 2013, 11:34:36 AM5/16/13
to freshbo...@googlegroups.com
Hi Arpit,

This is signpost code that works for us..... Be sure to tell signpost to user the Plain Text Signer

String requestTokenUrl = "https://" + url + ".freshbooks.com/oauth/oauth_request.php";
String accessTokenUrl = "https://" + url + ".freshbooks.com/oauth/oauth_access.php";
String authorizeUrl = "https://" + url + ".freshbooks.com/oauth/oauth_authorize.php";


        OAuthConsumer consumer = new DefaultOAuthConsumer(
                consumerKey, consumerSecret
                );
 
     consumer.setMessageSigner(new PlainTextMessageSigner());

        OAuthProvider provider = new DefaultOAuthProvider(
                requestTokenUrl,
                accessTokenUrl,
                authorizeUrl
                );

provider.setOAuth10a(true);

        authorizationUrl = provider.retrieveRequestToken(consumer, callbackUrl);

        System.out.println("Request token: " + consumer.getToken());
        System.out.println("Token secret: " + consumer.getTokenSecret());



Arpit Garg

unread,
May 16, 2013, 1:12:35 PM5/16/13
to freshbo...@googlegroups.com
Hello. This is great, it helps and helps me to proceed and it works. Many thanks for explicit and quick support and this has helped in resolving my issue.
thanks a lot.

- arpit

Arpit Garg

unread,
May 16, 2013, 10:33:49 PM5/16/13
to freshbo...@googlegroups.com
hello steve,
one problem which i am having now is how to use signpost to get staff.list or invoice.list data from freshbooks. is this possible or i have to write my own code using httppost and others to get response.
what i need now once authentication is done is to get data out of freshbooks ..
i tried as below but getting authentication failure (20010) in line highlighted in bold below

final String CONSUMER_KEY = "myaccounts";
final String CONSUMER_SECRET = "oauthsecret";

final String APPLICATION_NAME = "signpost-test";
final String freshbooks_REQUEST_TOKEN_URL = "https://mydomain.freshbooks.com/oauth/oauth_request.php";
    final String freshbooks_ACCESS_TOKEN_URL = "https://
mydomain.freshbooks.com/oauth/oauth_access.php";
    final String freshbooks_AUTHORIZE_URL = "https://
mydomain.freshbooks.com/oauth/oauth_authorize.php";
    String callbackUrl = "none";

     OAuthConsumer consumer = new DefaultOAuthConsumer(CONSUMER_KEY, CONSUMER_SECRET);
     consumer.setMessageSigner(new PlainTextMessageSigner());

        OAuthProvider provider = new DefaultOAuthProvider(freshbooks_REQUEST_TOKEN_URL,
            freshbooks_ACCESS_TOKEN_URL, freshbooks_AUTHORIZE_URL);
provider.setOAuth10a(true);

        System.out.println("Fetching request token from freshbooks...");

        // we do not support callbacks, thus pass OOB
        String authUrl = provider.retrieveRequestToken(consumer, //OAuth.OUT_OF_BAND
  callbackUrl      );

        authUrl = OAuth.addQueryParameters(authUrl, OAuth.OAUTH_CONSUMER_KEY, CONSUMER_KEY,
            "application_name", APPLICATION_NAME);

        System.out.println("Request token: " + consumer.getToken());
        System.out.println("Token secret: " + consumer.getTokenSecret());
       
HttpPost request = new HttpPost( "https://mydomain.freshbooks.com/api/2.1/xml-in" );

StringEntity se = new StringEntity("<request method=\"staff.list\"></request>","UTF-8");
//se.setContentType("text/xml");
request.addHeader( "Authorization", "Basic "+consumer.getTokenSecret());

request.addHeader("Content-Type","application/x-www-form-urlencoded");
request.setEntity(se);
// View response
System.out.println("RESPONSE START");
HttpClient client = new DefaultHttpClient();
HttpResponse response = client.execute(request);
HttpEntity entity = response.getEntity();
String inputLine ;
BufferedReader in = new BufferedReader(new InputStreamReader(entity.getContent()));
try {
while ((inputLine = in.readLine()) != null) {
System.out.println(inputLine);
}
in.close();
} catch (IOException e) {
e.printStackTrace();
}
System.out.println("RESPONSE END");

On Thursday, May 16, 2013 9:04:36 PM UTC+5:30, itDuzzit Steve wrote:

Arpit Garg

unread,
May 17, 2013, 5:21:59 AM5/17/13
to freshbo...@googlegroups.com
Hello Steve/Anton,
I am trying code below - but i get UnAuthorized error (or) /  404 Page Not found error - based on what i enter as URL.
In code below when i use
URL url = new URL("https://MyLogin.freshbooks.com/api/2.1/xml-in -d '<request method=\"invoice.list\" />'"); (I get 404 page not found)
URL url = new URL("https://MyLogin.freshbooks.com/api/2.1/xml-in"); (Response: 401 Unauthorized)

I guess i am messing up with tokens to be passed and syntax and encoding -  once i have obtained them from freshbooks.
I am not sure i am in right direction as what i want to do is below
1) develop a java code which will accept input as customerfreshbookkey (his mylogin.freshbooks.com) and also his oAuthSecret key (which he will get after registering for oAuthAPI().
2) With above i want to get data out of freshbooks for this customer from invoice.list, staff.list and others similar list in java, which will be used for reporting.
3) I guess for step#2 i have to get customers oAuthSecret key - and they have to request for freshbooks API - or is it possible that customer can get their using java from freshbooks api without even registering for freshbook API()? Let me know your thoughts.

I plan to do it as below - to which i could proceed to some extent (with blessings from you and Anton) but i am still not able to do what i require.
So again requesting your help.


import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import oauth.signpost.OAuth;
import oauth.signpost.OAuthConsumer;
import oauth.signpost.OAuthProvider;
import oauth.signpost.basic.DefaultOAuthConsumer;
import oauth.signpost.basic.DefaultOAuthProvider;
import oauth.signpost.signature.PlainTextMessageSigner;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.HttpEntity;
import org.apache.http.client.HttpClient;
import org.apache.http.HttpResponse;
import org.apache.http.impl.client.DefaultHttpClient;
import java.net.URLEncoder;
import java.util.UUID;
import java.security.GeneralSecurityException;
import org.apache.commons.codec.binary.Base64;
import org.apache.http.impl.client.BasicResponseHandler;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.ClientProtocolException;

String uuid_string = UUID.randomUUID().toString();
uuid_string = uuid_string.replaceAll("-", "");
String keySecret = new String(Base64.encodeBase64("MyAccountOAuthSecret".getBytes()));

String oauth_nonce = uuid_string; // any relatively random alphanumeric string will work here. I used UUID minus "-" signs
String oauth_timestamp = "1318467427";
final String CONSUMER_KEY = "MyLogin";
final String CONSUMER_SECRET = "MyAccountOAuthSecret";

final String APPLICATION_NAME = "signpost-test";
final String freshbooks_REQUEST_TOKEN_URL = "https://MyLogin.freshbooks.com/oauth/oauth_request.php";
    final String freshbooks_ACCESS_TOKEN_URL = "https://MyLogin.freshbooks.com/oauth/oauth_access.php";
    final String freshbooks_AUTHORIZE_URL = "https://MyLogin.freshbooks.com/oauth/oauth_authorize.php";
    String callbackUrl = "na";

     OAuthConsumer consumer = new DefaultOAuthConsumer(CONSUMER_KEY, CONSUMER_SECRET);
     consumer.setMessageSigner(new PlainTextMessageSigner());

        OAuthProvider provider = new DefaultOAuthProvider(freshbooks_REQUEST_TOKEN_URL,
            freshbooks_ACCESS_TOKEN_URL, freshbooks_AUTHORIZE_URL);
provider.setOAuth10a(true);
        System.out.println("Fetching request token from freshbooks...");

        // we do not support callbacks, thus pass OOB
        String authUrl = provider.retrieveRequestToken(consumer, OAuth.OUT_OF_BAND
  //callbackUrl     
  );
        authUrl = OAuth.addQueryParameters(authUrl, OAuth.OAUTH_CONSUMER_KEY, CONSUMER_KEY,
            "application_name", APPLICATION_NAME);

        System.out.println("Request token: " + consumer.getToken());
        System.out.println("Token secret: " + consumer.getTokenSecret());

//URL url = new URL("https://MyLogin.freshbooks.com/api/2.1/xml-in -d '<request method=\"invoice.list\" />'");
URL url = new URL("https://MyLogin.freshbooks.com/api/2.1/xml-in");
        HttpURLConnection request = (HttpURLConnection) url.openConnection();
        consumer.sign(request);
        System.out.println("Sending request to freshbooks...");
   
    String data = "OAuth realm=\"\", oauth_nonce=\"" + oauth_nonce
    + "\", oauth_signature_method=\"PLAINTEXT"
    + "\", oauth_timestamp=\"" + oauth_timestamp
    + "\", oauth_consumer_key=\"" + CONSUMER_KEY
    + "\", oauth_callback=\"none"
    + "\", oauth_token=\"" + consumer.getToken()
    + "\", oauth_signature=\"" + keySecret +"%2526"+ consumer.getTokenSecret()   
    + "\", oauth_version=\"1.0\"";       
    System.out.println(data);
        request.setRequestProperty("Authorization", data);
        request.setRequestMethod("POST");
        request.connect();
//i Get error here.
        System.out.println("Response: " + request.getResponseCode() + " "
                + request.getResponseMessage()); 

Logs given below
-------------------------------------------

Fetching request token from freshbooks...
Request token: 4vk5BsJGchB9VHgxBMimJfZUEzVEMF9Eb
Token secret: pPWqaYRa7aLsxCBEZSbpnVc5xEziFk7nT
https://notapplicable-accounts.freshbooks.com/api/2.1/xml-in
Sending request to freshbooks...
OAuth realm="", oauth_nonce="162abd35739b48eaa342fea28e41b6c9", oauth_signature_method="PLAINTEXT", oauth_timestamp="1318467427", oauth_consumer_key="notapplicable-accounts", oauth_callback="none", oauth_token="4vk5BsJGchB9VHgxBMimJfZUEzVEMF9Eb", oauth_signature="a3JhenNyVURnN1BDRjhNSnhFQnM1YmR3WjdxVXRZV2Jj%2526pPWqaYRa7aLsxCBEZSbpnVc5xEziFk7nT", oauth_version="1.0"
Response: 401 Unauthorized
[statistics] disconnected

Anton Nguyen

unread,
May 17, 2013, 6:01:24 AM5/17/13
to freshbo...@googlegroups.com
Hey Arpit,

First off,
URL url = new URL("https://MyLogin.freshbooks.com/api/2.1/xml-in -d '<request method=\"invoice.list\" />'"); (I get 404 page not found)

This gives you a 404 error because "https://MyLogin.freshbooks.com/api/2.1/xml-in -d '<request method=\"invoice.list\" />'" is not a valid URL. I think you were looking at my 'Oauth Dance' example, and copy and pasted from the curl command. The "-d" part is simply a parameter that tells curl, 'this is the data I want when I make a post". So your URL should only be "https://notapplicable-accounts.freshbooks.com/api/2.1/xml-in".

To send XML data to FreshBooks, I would probably use the HttpPost class:
        // Build a string Entity for the POST body
        StringEntity xml = new StringEntity("<?xml version='1.0' encoding='utf-8' ?><request method=\"invoice.list\"></request>", "UTF-8");

        HttpPost request = new HttpPost( "https://notapplicable-accounts.freshbooks.com/api/2.1/xml-in" );
        request.addHeader( "Authorization", data); // Pass in the OAuth parameters you built up
        request.addHeader( "Content-Type", "application/x-www-form-urlencoded");
        request.addHeader( "User-Agent", "FreshBooks-Java" );
        request.removeHeaders( "Content-Length" );
        request.setEntity( string );

        // Make a request
        DefaultHttpClient client = new DefaultHttpClient();
        HttpResponse response = client.execute(request);

        // Examine the response
        HttpEntity entity = response.getEntity();
        String inputLine ;
        BufferedReader in = new BufferedReader(new InputStreamReader(entity.getContent()));
        try {
           while ((inputLine = in.readLine()) != null) {
                  System.out.println(inputLine);
           }
           in.close();
        } catch (IOException e) {
           e.printStackTrace();
        }

I haven't tested the above code out yet, but if it doesn't work, I'll try again once I get into the office. 

Secondly, looking at your OAuth Authorization headers, 

OAuth realm="", oauth_nonce="162abd35739b48eaa342fea28e41b6c9", oauth_signature_method="PLAINTEXT", oauth_timestamp="1318467427", oauth_consumer_key="notapplicable-accounts", oauth_callback="none", oauth_token="4vk5BsJGchB9VHgxBMimJfZUEzVEMF9Eb", oauth_signature="a3JhenNyVURnN1BDRjhNSnhFQnM1YmR3WjdxVXRZV2Jj%2526pPWqaYRa7aLsxCBEZSbpnVc5xEziFk7nT", oauth_version="1.0"

It seems like you never actually completed the OAuth dance. You've only completed the very first step, "Obtaining an OAuth Request Token", and you're now trying to use the OAuth token and OAuth secret from that response. You still need to get a verifier and request the access tokens.

To get your verifier, simply go to https://notapplicable-accounts.freshbooks.com/oauth/oauth_authorize.php?oauth_token= 4vk5BsJGchB9VHgxBMimJfZUEzVEMF9Eb, and sign in to authorize the consumer to access your data. Your oauth_callback is not a URI format, so the verifier token will be display on the page. Once you get the verifier token, you'll be able to "Obtain an Access Token" and finally make API calls.

Another problem I see with your header, is the consumer_secret in your oauth_signature. Right now, its set to "a3JhenNyVURnN1BDRjhNSnhFQnM1YmR3WjdxVXRZV2J" which doesn't match what's in your account. I believe its due to this line:
String keySecret = new String(Base64.encodeBase64("MyAccountOAuthSecret".getBytes()));

You don't need to base64 encode your OAuth Secret. Remember, this is only if you're doing Basic Token Authentication, not OAuth Authentication.

Barum and myself have asked you before, but I'll ask again. Do you need to use OAuth? I'd only use OAuth if I wanted my application to talk to many different people's FreshBooks account. If my application only needed to talk to one account, I would stick to Basic.

Finally, to answer questions about your workflow, you wrote, 
"I guess for step#2 i have to get customers oAuthSecret key - and they have to request for freshbooks API - or is it possible that customer can get their using java from freshbooks api without even registering for freshbook API()? Let me know your thoughts."

So that's the entire point of OAuth. Once you have a consumer account, whom you've setup to have OAuth access (ie. notapplicable-accounts.freshbooks.com), once you initiate the dance with another user's FreshBooks account, the other user simply has to give permission for notapplicable-accounts to access your data. This means that customer does not need to register for OAuth, and you'll be able to access their data and generate your reports.

I hope that makes sense. I urge you to go through the The OAuth Dance with FreshBooks guide I wrote just for you, and actually try the "Oauth Dance Example" curl examples inside terminal if you wish to continue using OAuth. There's a lot of confusion, that could of been avoided if you had simply familiarized yourself a bit more with how it works.

Let me know if you have anymore questions!
Anton

Anton Nguyen

unread,
May 17, 2013, 7:18:31 AM5/17/13
to freshbo...@googlegroups.com
Hey Arpit,

In case you need it, here's a working example of Basic Authentication:

Anton

Arpit Garg

unread,
May 17, 2013, 7:28:41 AM5/17/13
to freshbo...@googlegroups.com
Hey Anton,
Sorry for all the trouble and confusion i had created. Thanks to you and team for help.
Yes this is exactly what i was looking for.

- arpit

Bharat Satija

unread,
Sep 13, 2014, 3:55:01 AM9/13/14
to freshbo...@googlegroups.com
Hi Anton, 

I have API URL, Authentication Token, OAuth Secret.

I am unable to fetch Request Token it's giving me 404 error. The code i am using is given below.

        URL obj = new URL(url);
        HttpsURLConnection con = (HttpsURLConnection) obj.openConnection();
        con.setRequestMethod("POST");
        con.setRequestProperty("oauth_consumer_key", "OAuth Secret");
        con.setRequestProperty("oauth_token", "Authentication Token");
        con.setRequestProperty("oauth_signature", "Authentication Token"+".&.OAuth Secret");
        con.setRequestProperty("oauth_version", "1.0");
        con.setRequestProperty("oauth_signature_method", "PLAINTEXT");
        con.setRequestProperty("oauth_callback", "Call Back Url");
        con.setRequestProperty("oauth_nonce",  "x"+System.currentTimeMillis());
        con.setRequestProperty("oauth_timestamp", "${System.currentTimeMillis()/1000}");

        con.setDoOutput(true);
        
        DataOutputStream wr = new DataOutputStream(con.getOutputStream());
        wr.writeBytes("");
        wr.flush();
        wr.close();

        BufferedReader bufferedReader = new BufferedReader(
                new InputStreamReader(con.getInputStream()));
        String inputLine;
        StringBuffer response = new StringBuffer();

        while ((inputLine = bufferedReader.readLine()) != null) {
            response.append(inputLine);
        }
        
        bufferedReader.close();

  Can you please suggest me the bug in this code. So, that i would be able to fetch request token.

Thanks 
Bharat Satija
Reply all
Reply to author
Forward
0 new messages