├── .classpath
├── .gitignore
├── .project
├── .settings
├── org.eclipse.jdt.core.prefs
└── org.maven.ide.eclipse.prefs
├── AndroidManifest.xml
├── README
├── default.properties
├── pom.xml
├── res
├── drawable-hdpi
│ └── icon.png
├── drawable-ldpi
│ └── icon.png
├── drawable-mdpi
│ └── icon.png
├── layout
│ └── main.xml
└── values
│ └── strings.xml
└── src
└── com
└── ecs
└── android
└── oauth
├── Constants.java
├── OAuthFlowApp.java
├── OAuthRequestTokenTask.java
├── PrepareRequestTokenActivity.java
└── RetrieveAccessTokenTask.java
/.classpath:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /bin
2 | /target
3 |
--------------------------------------------------------------------------------
/.project:
--------------------------------------------------------------------------------
1 |
2 |
3 | AndroidOAuthFlowSample
4 |
5 |
6 |
7 |
8 |
9 | com.android.ide.eclipse.adt.ResourceManagerBuilder
10 |
11 |
12 |
13 |
14 | com.android.ide.eclipse.adt.PreCompilerBuilder
15 |
16 |
17 |
18 |
19 | org.eclipse.jdt.core.javabuilder
20 |
21 |
22 |
23 |
24 | org.maven.ide.eclipse.maven2Builder
25 |
26 |
27 |
28 |
29 |
30 | org.maven.ide.eclipse.maven2Nature
31 | com.android.ide.eclipse.adt.AndroidNature
32 | org.eclipse.jdt.core.javanature
33 |
34 |
35 |
--------------------------------------------------------------------------------
/.settings/org.eclipse.jdt.core.prefs:
--------------------------------------------------------------------------------
1 | #Tue Dec 14 17:42:58 CET 2010
2 | eclipse.preferences.version=1
3 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
4 | org.eclipse.jdt.core.compiler.compliance=1.6
5 | org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
6 | org.eclipse.jdt.core.compiler.source=1.6
7 |
--------------------------------------------------------------------------------
/.settings/org.maven.ide.eclipse.prefs:
--------------------------------------------------------------------------------
1 | #Mon Dec 13 19:22:47 CET 2010
2 | activeProfiles=
3 | eclipse.preferences.version=1
4 | fullBuildGoals=process-test-resources
5 | resolveWorkspaceProjects=true
6 | resourceFilterGoals=process-resources resources\:testResources
7 | skipCompilerPlugin=true
8 | version=1
9 |
--------------------------------------------------------------------------------
/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
9 |
10 |
11 |
13 |
14 |
15 |
16 |
17 |
18 |
19 | >
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/README:
--------------------------------------------------------------------------------
1 | Sample Android app that does the OAuth Dance.
2 |
3 | Accompanying article can be found here :
4 |
5 | http://blog.doityourselfandroid.com/2010/11/10/oauth-flow-in-android-app/
6 |
7 | Goes through all the steps of the OAuth Flow
8 |
9 | * Get Request Token
10 | * Authorize Token
11 | * Get Access Token
12 | * Perform Google API call (retrieve contacts).
13 |
--------------------------------------------------------------------------------
/default.properties:
--------------------------------------------------------------------------------
1 | # This file is automatically generated by Android Tools.
2 | # Do not modify this file -- YOUR CHANGES WILL BE ERASED!
3 | #
4 | # This file must be checked in Version Control Systems.
5 | #
6 | # To customize properties used by the Ant build system use,
7 | # "build.properties", and override values to adapt the script to your
8 | # project structure.
9 |
10 | # Project target.
11 | target=android-4
12 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 4.0.0
4 | com.ecs
5 | AndroidOAuthFlowSample
6 | apk
7 | 0.0.1-SNAPSHOT
8 | AndroidOAuthFlowSample
9 |
10 |
11 |
12 | com.google.android
13 | android
14 | 1.6_r2
15 | provided
16 |
17 |
18 | oauth.signpost
19 | signpost-core
20 | 1.2.1.1
21 |
22 |
23 | oauth.signpost
24 | signpost-commonshttp4
25 | 1.2.1.1
26 |
27 |
28 | org.json
29 | json
30 | 20090211
31 |
32 |
33 |
34 |
35 | ${project.artifactId}
36 | src
37 |
38 |
39 | org.apache.maven.plugins
40 | maven-compiler-plugin
41 | 2.3.2
42 |
43 | 1.6
44 | 1.6
45 |
46 |
47 |
48 | com.jayway.maven.plugins.android.generation2
49 | maven-android-plugin
50 | 2.8.3
51 |
52 |
53 | 1.6
54 |
55 | true
56 |
57 | true
58 |
59 |
60 |
61 |
62 |
--------------------------------------------------------------------------------
/res/drawable-hdpi/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ddewaele/AndroidOAuthFlowSample/ae3ec71e8e7365644409ce93b5cf6f045a54a202/res/drawable-hdpi/icon.png
--------------------------------------------------------------------------------
/res/drawable-ldpi/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ddewaele/AndroidOAuthFlowSample/ae3ec71e8e7365644409ce93b5cf6f045a54a202/res/drawable-ldpi/icon.png
--------------------------------------------------------------------------------
/res/drawable-mdpi/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ddewaele/AndroidOAuthFlowSample/ae3ec71e8e7365644409ce93b5cf6f045a54a202/res/drawable-mdpi/icon.png
--------------------------------------------------------------------------------
/res/layout/main.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
11 |
12 |
16 |
17 |
23 |
24 |
--------------------------------------------------------------------------------
/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Hello World, OAuthFlowApp!
4 | AndroidOAuthFlow
5 |
6 |
--------------------------------------------------------------------------------
/src/com/ecs/android/oauth/Constants.java:
--------------------------------------------------------------------------------
1 | package com.ecs.android.oauth;
2 |
3 |
4 | public class Constants {
5 |
6 | public static final String CONSUMER_KEY = "anonymous";
7 | public static final String CONSUMER_SECRET = "anonymous";
8 |
9 | public static final String SCOPE = "https://www.google.com/m8/feeds/";
10 | public static final String REQUEST_URL = "https://www.google.com/accounts/OAuthGetRequestToken";
11 | public static final String ACCESS_URL = "https://www.google.com/accounts/OAuthGetAccessToken";
12 | public static final String AUTHORIZE_URL = "https://www.google.com/accounts/OAuthAuthorizeToken";
13 |
14 | public static final String API_REQUEST = "https://www.google.com/m8/feeds/contacts/default/full?alt=json";
15 |
16 | public static final String ENCODING = "UTF-8";
17 |
18 | public static final String OAUTH_CALLBACK_SCHEME = "x-oauthflow";
19 | public static final String OAUTH_CALLBACK_HOST = "callback";
20 | public static final String OAUTH_CALLBACK_URL = OAUTH_CALLBACK_SCHEME + "://" + OAUTH_CALLBACK_HOST;
21 |
22 | }
23 |
--------------------------------------------------------------------------------
/src/com/ecs/android/oauth/OAuthFlowApp.java:
--------------------------------------------------------------------------------
1 | package com.ecs.android.oauth;
2 |
3 | import java.io.BufferedReader;
4 | import java.io.InputStream;
5 | import java.io.InputStreamReader;
6 |
7 | import oauth.signpost.OAuth;
8 | import oauth.signpost.OAuthConsumer;
9 | import oauth.signpost.commonshttp.CommonsHttpOAuthConsumer;
10 |
11 | import org.apache.http.HttpResponse;
12 | import org.apache.http.client.methods.HttpGet;
13 | import org.apache.http.impl.client.DefaultHttpClient;
14 | import org.json.JSONArray;
15 | import org.json.JSONObject;
16 |
17 | import android.app.Activity;
18 | import android.content.Intent;
19 | import android.content.SharedPreferences;
20 | import android.content.SharedPreferences.Editor;
21 | import android.database.Cursor;
22 | import android.net.Uri;
23 | import android.os.Bundle;
24 | import android.preference.PreferenceManager;
25 | import android.provider.Contacts.People;
26 | import android.util.Log;
27 | import android.view.View;
28 | import android.widget.Button;
29 | import android.widget.TextView;
30 |
31 | /**
32 | * Entry point in the application.
33 | * Launches the OAuth flow by starting the PrepareRequestTokenActivity
34 | *
35 | */
36 | public class OAuthFlowApp extends Activity {
37 |
38 | private static final int PICK_CONTACT = 0;
39 | final String TAG = getClass().getName();
40 | private SharedPreferences prefs;
41 |
42 | @Override
43 | public void onCreate(Bundle savedInstanceState) {
44 | super.onCreate(savedInstanceState);
45 | setContentView(R.layout.main);
46 | this.prefs = PreferenceManager.getDefaultSharedPreferences(this);
47 |
48 | Button launchOauth = (Button) findViewById(R.id.btn_launch_oauth);
49 | Button clearCredentials = (Button) findViewById(R.id.btn_clear_credentials);
50 |
51 | launchOauth.setOnClickListener(new View.OnClickListener() {
52 | public void onClick(View v) {
53 | startActivity(new Intent().setClass(v.getContext(), PrepareRequestTokenActivity.class));
54 | }
55 | });
56 |
57 | clearCredentials.setOnClickListener(new View.OnClickListener() {
58 | public void onClick(View v) {
59 | clearCredentials();
60 | performApiCall();
61 | }
62 | });
63 |
64 |
65 | performApiCall();
66 | }
67 |
68 | private void performApiCall() {
69 | TextView textView = (TextView) findViewById(R.id.response_code);
70 |
71 | String jsonOutput = "";
72 | try {
73 | jsonOutput = doGet(Constants.API_REQUEST,getConsumer(this.prefs));
74 | System.out.println("jsonOutput : " + jsonOutput);
75 | JSONObject jsonResponse = new JSONObject(jsonOutput);
76 | JSONObject m = (JSONObject)jsonResponse.get("feed");
77 | JSONArray entries =(JSONArray)m.getJSONArray("entry");
78 | String contacts="";
79 | for (int i=0 ; i0) {
83 | contacts+=title.getString("$t") + "\n";
84 | }
85 | }
86 | Log.i(TAG,jsonOutput);
87 | textView.setText(contacts);
88 | } catch (Exception e) {
89 | Log.e(TAG, "Error executing request",e);
90 | textView.setText("Error retrieving contacts : " + jsonOutput);
91 | }
92 | }
93 |
94 | public void onActivityResult(int reqCode, int resultCode, Intent data) {
95 | super.onActivityResult(reqCode, resultCode, data);
96 |
97 | switch (reqCode) {
98 | case (PICK_CONTACT) :
99 | if (resultCode == Activity.RESULT_OK) {
100 | Uri contactData = data.getData();
101 | Cursor c = managedQuery(contactData, null, null, null, null);
102 | if (c.moveToFirst()) {
103 | String name = c.getString(c.getColumnIndexOrThrow(People.NAME));
104 | Log.i(TAG,"Response : " + "Selected contact : " + name);
105 | }
106 | }
107 | break;
108 | }
109 | }
110 |
111 | private void clearCredentials() {
112 | SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
113 | final Editor edit = prefs.edit();
114 | edit.remove(OAuth.OAUTH_TOKEN);
115 | edit.remove(OAuth.OAUTH_TOKEN_SECRET);
116 | edit.commit();
117 | }
118 |
119 |
120 | private OAuthConsumer getConsumer(SharedPreferences prefs) {
121 | String token = prefs.getString(OAuth.OAUTH_TOKEN, "");
122 | String secret = prefs.getString(OAuth.OAUTH_TOKEN_SECRET, "");
123 | OAuthConsumer consumer = new CommonsHttpOAuthConsumer(Constants.CONSUMER_KEY, Constants.CONSUMER_SECRET);
124 | consumer.setTokenWithSecret(token, secret);
125 | return consumer;
126 | }
127 |
128 | private String doGet(String url,OAuthConsumer consumer) throws Exception {
129 | DefaultHttpClient httpclient = new DefaultHttpClient();
130 | HttpGet request = new HttpGet(url);
131 | Log.i(TAG,"Requesting URL : " + url);
132 | consumer.sign(request);
133 | HttpResponse response = httpclient.execute(request);
134 | Log.i(TAG,"Statusline : " + response.getStatusLine());
135 | InputStream data = response.getEntity().getContent();
136 | BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(data));
137 | String responeLine;
138 | StringBuilder responseBuilder = new StringBuilder();
139 | while ((responeLine = bufferedReader.readLine()) != null) {
140 | responseBuilder.append(responeLine);
141 | }
142 | Log.i(TAG,"Response : " + responseBuilder.toString());
143 | return responseBuilder.toString();
144 | }
145 | }
--------------------------------------------------------------------------------
/src/com/ecs/android/oauth/OAuthRequestTokenTask.java:
--------------------------------------------------------------------------------
1 | package com.ecs.android.oauth;
2 |
3 | import oauth.signpost.OAuthConsumer;
4 | import oauth.signpost.OAuthProvider;
5 | import android.content.Context;
6 | import android.content.Intent;
7 | import android.net.Uri;
8 | import android.os.AsyncTask;
9 | import android.util.Log;
10 |
11 | /**
12 | * An asynchronous task that communicates with Google to
13 | * retrieve a request token.
14 | * (OAuthGetRequestToken)
15 | *
16 | * After receiving the request token from Google,
17 | * show a browser to the user to authorize the Request Token.
18 | * (OAuthAuthorizeToken)
19 | *
20 | */
21 | public class OAuthRequestTokenTask extends AsyncTask {
22 |
23 | final String TAG = getClass().getName();
24 | private Context context;
25 | private OAuthProvider provider;
26 | private OAuthConsumer consumer;
27 |
28 | /**
29 | *
30 | * We pass the OAuth consumer and provider.
31 | *
32 | * @param context
33 | * Required to be able to start the intent to launch the browser.
34 | * @param provider
35 | * The OAuthProvider object
36 | * @param consumer
37 | * The OAuthConsumer object
38 | */
39 | public OAuthRequestTokenTask(Context context,OAuthConsumer consumer,OAuthProvider provider) {
40 | this.context = context;
41 | this.consumer = consumer;
42 | this.provider = provider;
43 | }
44 |
45 | /**
46 | *
47 | * Retrieve the OAuth Request Token and present a browser to the user to authorize the token.
48 | *
49 | */
50 | @Override
51 | protected Void doInBackground(Void... params) {
52 |
53 | try {
54 | Log.i(TAG, "Retrieving request token from Google servers");
55 | final String url = provider.retrieveRequestToken(consumer, Constants.OAUTH_CALLBACK_URL);
56 | Log.i(TAG, "Popping a browser with the authorize URL : " + url);
57 | Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url)).setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_NO_HISTORY | Intent.FLAG_FROM_BACKGROUND);
58 | context.startActivity(intent);
59 |
60 | } catch (Exception e) {
61 | Log.e(TAG, "Error during OAUth retrieve request token", e);
62 | }
63 |
64 | return null;
65 | }
66 |
67 | }
--------------------------------------------------------------------------------
/src/com/ecs/android/oauth/PrepareRequestTokenActivity.java:
--------------------------------------------------------------------------------
1 | package com.ecs.android.oauth;
2 |
3 | import java.net.URLEncoder;
4 |
5 | import oauth.signpost.OAuthConsumer;
6 | import oauth.signpost.OAuthProvider;
7 | import oauth.signpost.commonshttp.CommonsHttpOAuthConsumer;
8 | import oauth.signpost.commonshttp.CommonsHttpOAuthProvider;
9 | import android.app.Activity;
10 | import android.content.Intent;
11 | import android.content.SharedPreferences;
12 | import android.net.Uri;
13 | import android.os.Bundle;
14 | import android.preference.PreferenceManager;
15 | import android.util.Log;
16 |
17 | /**
18 | * Prepares a OAuthConsumer and OAuthProvider
19 | *
20 | * OAuthConsumer is configured with the consumer key & consumer secret.
21 | * OAuthProvider is configured with the 3 OAuth endpoints.
22 | *
23 | * Execute the OAuthRequestTokenTask to retrieve the request, and authorize the request.
24 | *
25 | * After the request is authorized, a callback is made here.
26 | *
27 | */
28 | public class PrepareRequestTokenActivity extends Activity {
29 |
30 | final String TAG = getClass().getName();
31 |
32 | private OAuthConsumer consumer;
33 | private OAuthProvider provider;
34 |
35 | @Override
36 | public void onCreate(Bundle savedInstanceState) {
37 | super.onCreate(savedInstanceState);
38 | try {
39 | System.setProperty("debug", "true");
40 | this.consumer = new CommonsHttpOAuthConsumer(Constants.CONSUMER_KEY, Constants.CONSUMER_SECRET);
41 | this.provider = new CommonsHttpOAuthProvider(
42 | Constants.REQUEST_URL + "?scope=" + URLEncoder.encode(Constants.SCOPE, Constants.ENCODING),
43 | Constants.ACCESS_URL,
44 | Constants.AUTHORIZE_URL);
45 | } catch (Exception e) {
46 | Log.e(TAG, "Error creating consumer / provider",e);
47 | }
48 |
49 | Log.i(TAG, "Starting task to retrieve request token.");
50 | new OAuthRequestTokenTask(this,consumer,provider).execute();
51 | }
52 |
53 | /**
54 | * Called when the OAuthRequestTokenTask finishes (user has authorized the request token).
55 | * The callback URL will be intercepted here.
56 | */
57 | @Override
58 | public void onNewIntent(Intent intent) {
59 | super.onNewIntent(intent);
60 | SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
61 | final Uri uri = intent.getData();
62 | if (uri != null && uri.getScheme().equals(Constants.OAUTH_CALLBACK_SCHEME)) {
63 | Log.i(TAG, "Callback received : " + uri);
64 | Log.i(TAG, "Retrieving Access Token");
65 | new RetrieveAccessTokenTask(this,consumer,provider,prefs).execute(uri);
66 | finish();
67 | }
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/src/com/ecs/android/oauth/RetrieveAccessTokenTask.java:
--------------------------------------------------------------------------------
1 | package com.ecs.android.oauth;
2 |
3 | import oauth.signpost.OAuth;
4 | import oauth.signpost.OAuthConsumer;
5 | import oauth.signpost.OAuthProvider;
6 | import android.content.Context;
7 | import android.content.Intent;
8 | import android.content.SharedPreferences;
9 | import android.content.SharedPreferences.Editor;
10 | import android.net.Uri;
11 | import android.os.AsyncTask;
12 | import android.util.Log;
13 |
14 | public class RetrieveAccessTokenTask extends AsyncTask {
15 |
16 | final String TAG = getClass().getName();
17 |
18 | private Context context;
19 | private OAuthProvider provider;
20 | private OAuthConsumer consumer;
21 | private SharedPreferences prefs;
22 |
23 | public RetrieveAccessTokenTask(Context context, OAuthConsumer consumer,OAuthProvider provider, SharedPreferences prefs) {
24 | this.context = context;
25 | this.consumer = consumer;
26 | this.provider = provider;
27 | this.prefs=prefs;
28 | }
29 |
30 |
31 | /**
32 | * Retrieve the oauth_verifier, and store the oauth and oauth_token_secret
33 | * for future API calls.
34 | */
35 | @Override
36 | protected Void doInBackground(Uri...params) {
37 | final Uri uri = params[0];
38 |
39 |
40 | final String oauth_verifier = uri.getQueryParameter(OAuth.OAUTH_VERIFIER);
41 |
42 | try {
43 | provider.retrieveAccessToken(consumer, oauth_verifier);
44 |
45 | final Editor edit = prefs.edit();
46 | edit.putString(OAuth.OAUTH_TOKEN, consumer.getToken());
47 | edit.putString(OAuth.OAUTH_TOKEN_SECRET, consumer.getTokenSecret());
48 | edit.commit();
49 |
50 | String token = prefs.getString(OAuth.OAUTH_TOKEN, "");
51 | String secret = prefs.getString(OAuth.OAUTH_TOKEN_SECRET, "");
52 |
53 | consumer.setTokenWithSecret(token, secret);
54 | context.startActivity(new Intent(context,OAuthFlowApp.class));
55 |
56 | Log.i(TAG, "OAuth - Access Token Retrieved");
57 |
58 | } catch (Exception e) {
59 | Log.e(TAG, "OAuth - Access Token Retrieval Error", e);
60 | }
61 |
62 | return null;
63 | }
64 | }
--------------------------------------------------------------------------------