The Racó has API that is accessible via OAuth. Using it from a mobile application is not a simple task. In this article we will try to see how to do it from Android. At the same time, this serves as an example of how to use this kind of authentication in any other API that works with OAuth.
First of all, we will assume certain minimum knowledge on Android development.
The Racó has API that is accessible via OAuth. Using it from a mobile application is not a simple task. In this article we will try to see how to do it from Android. At the same time, this serves as an example of how to use this kind of authentication in any other API that works with OAuth.
First of all, we will assume certain minimum knowledge on Android development. In particular, in order to follow this tutorial we will need
- A correctly configured Android development environment, with Ecplise and ADT. See how to install Eclipse and ADT plugins
- Basic knowledge: what are Android Activities, Intent and Intent Filters and AsyncTasks
- Essential concept of OAuth
If we have these, let’s get to work (or code, in this case).
The choreography
OAuth flux is also known as the OAuth dance, which is what allows our system to authorize third-party applications to access our information. In this case, any Racó user may give permission from the Racó for an application to access their personal data.
The dance consists of three steps: request, authorization and access. Before this, however, we will have to properly introduce the dancers to one another: the Racó has to meet the application it will dance with.
Meeting our dancing partner: registering the application
Any application that needs to access Racó information has to be registered previously. The URL to register a new application is https://raco.fib.upc.edu/oauth/gestio-api/register.jsp
Once the application has been registered, the Racó will generate two values: the key and the secret. This couple of values will be integrated in every request to the Racó, so that each request leaves track of what application has made it. The key just another value passed within the request and the secret is used as the key to generate a request digital signature. As we will see later on, using a specific OAuth library will abstract us from these details: we just need to bear in mind that requests between the application and the Racó are signed.
First step: Request
In this step the application we are developing asks the Racó for a token by sending a signed request. The Racó returns a token named “request token”.
Second step: Authorization
The way to authorize this request token is to display a screen of the Racó to which we’ll pass the request token as a parameter. If the application user accepts it, the Racó will save the request token has been validated and it will return a redirection towards our application named Callback URL. To sum up: the user validates the token from the Racó and once it has been validated, control is taken back by the Android application.
Third step: Access
At this moment, we have a validated request token and it should be exchanged by an access token. Again, this involves another signed request with the application keys to a different URL. This request will return a new token, which is the one our application will save and will allow us to access the information the user has authorized. You may now be wondering… why go on such a hassle for this token? Could not we just use the one we had before? Well, the answer is no, since we have seen the request token in the URL, whereas information exchange by access token does not involve any kind of web interaction with the user. This way, it remains entirely between the Racó and the application. The key to OAuth security is that everything remains secret.
These three steps only have to be followed once. As long as the application keeps the access token and this one does not expire user data may be accessed without having to validate or authorize again.
Step by step
Since we now know our choreography. Let’s do this again step by step with music (or code if you prefer).
First of all we will need a library that allows us to sign requests following the OAuth protocol. We will use the SignPost library, which is very easy to use. We will initialize the library with the basic data: application keys and URL of the different steps. SignPost gives us a Provider (object that abstracts us from the Racó) and a Consumer (that represents the application we are developing). And so, our Activity will have the following attributes:
OAuthProvider provider = new DefaultOAuthProvider( "https://raco.fib.upc.edu/oauth/request_token", "https://raco.fib.upc.edu/oauth/access_token", "https://raco.fib.upc.edu/oauth/protected/authorize"); String callback="raco://raco"; String key="4812b0b0-b1a9-11e2-9e96-0800200c9a66"; String secret="54efb080-b1a9-11e2-9e96-0800200c9a66"; DefaultOAuthConsumer consumer;
In order to request the request token, we find an Android limitation: we cannot include code that requests from the Internet in the main thread of the application, so we’ll make the request within an AsyncTask. When we have the token, we’ll save it (in the localStorage, for example) and we will open a browser with the token validation URL..
class DemanaRequestTokenAsync extends AsyncTask<Void, Void, String> { @Override protected String doInBackground(Void... params) { String authURL=null; try { authURL = provider.retrieveRequestToken(consumer, callback); guardaTokens(); } catch (Exception e) { e.printStackTrace(); } return authURL; } // When I have the token I open the browser. From event to event... // ¡Warning! Save the tokens before continuing @Override protected void onPostExecute(String authURL) { startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(authURL))); } }
When we validate the token in our browser, it will redirect us towards the callback URL, which will be like raco://raco. How do we make this run in our application instead of opening a new web page in our browser? Easy: we will use an Intent Filter that will associate this protocol with our Activity
<intent-filter> <action android:name="android.intent.action.VIEW"></action> <category android:name="android.intent.category.DEFAULT"></category> <category android:name="android.intent.category.BROWSABLE"></category> <data android:host="raco" android:scheme="raco"></data> </intent-filter>
public void onResume() { super.onResume(); Uri uri = this.getIntent().getData(); recuperaTokens(); // Este es el caso en que volvemos con token. Si no, no hacemos nada if (uri != null && uri.toString().startsWith(callback)) { new DemanaAccessTokenAsync().execute(); } }
As before, the code to request the access token has to be run asynchronously. So we have to create another AsyncTask, similar to the one we used to ask for the request token. The dance is over: we have what we wanted from our dance partners now
class DemanaAccessTokenAsync extends AsyncTask<Void, Void, Void> { @Override protected Void doInBackground(Void... params) { try { provider.retrieveAccessToken(consumer,null); guardaTokens(true); } catch (Exception e) { Log.d("oauth","ha petat al access token"); } return null; } // Once I have the token and the secret I can start working. @Override protected void onPostExecute(Void result) { // The consumer has been updated with the two access tokens that allow it to make requests // to our web services. These values have to be saved and do a // consumer.setTokenWithSecret if they exist. } }
The dance is over. But the best part stars now
Since we already have our precious access token, the dance partners know each other well enough and can start a conversation. As an example, we’ll request basic user information and we will obtain the full name. We can obtain many other things, which are listed in Racó API webpage. In the code we will use the object consumer that we have been using up until now to make these signed petitions, since it contains the access token. We may have the access token either because we’ve done the entire dance or because we have it stored from a previous request.
public String getNom() { String json=demana("https://raco.fib.upc.edu/api-v1/info-personal.json";); JSONObject jObject = new JSONObject(json); return jObject.getString("nom")); } private String demana (String url) { StringBuffer aux=new StringBuffer(); try { URL u = new URL(url); HttpURLConnection request = (HttpURLConnection) u.openConnection(); consumer.sign(request); BufferedReader in = new BufferedReader(new InputStreamReader( request.getInputStream())); String inputLine; while ((inputLine = in.readLine()) != null) { aux.append(inputLine); } } catch (Exception e) { Log.i("oauth",e.getMessage()); } return aux.toString(); }
Conclusiones
In this example we have seen how to use an API with OAuth 1.0 from Android using the SingPost library. Even though we have focused on the Racó example, this is applicable to any other web that uses OAuth 1.0. Many APIs, though, are already migrating to OAuth 2.0, since it simplifies access.