Skip to content

Instantly share code, notes, and snippets.

@TomTasche
Last active May 11, 2023 20:00
Show Gist options
  • Save TomTasche/5665497 to your computer and use it in GitHub Desktop.
Save TomTasche/5665497 to your computer and use it in GitHub Desktop.
OAuth flow using the AccountManager on Android
<!-- ... -->
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.USE_CREDENTIALS" />
<!-- ... -->
import android.accounts.Account;
import android.accounts.AccountManager;
import android.accounts.AccountManagerCallback;
import android.accounts.AccountManagerFuture;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
public class AuthActivity extends Activity {
private static final int AUTHORIZATION_CODE = 1993;
private static final int ACCOUNT_CODE = 1601;
private AuthPreferences authPreferences;
private AccountManager accountManager;
/**
* change this depending on the scope needed for the things you do in
* doCoolAuthenticatedStuff()
*/
private final String SCOPE = "https://www.googleapis.com/auth/googletalk";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
accountManager = AccountManager.get(this);
authPreferences = new AuthPreferences(this);
if (authPreferences.getUser() != null
&& authPreferences.getToken() != null) {
doCoolAuthenticatedStuff();
} else {
chooseAccount();
}
}
private void doCoolAuthenticatedStuff() {
// TODO: insert cool stuff with authPreferences.getToken()
Log.e("AuthApp", authPreferences.getToken());
}
private void chooseAccount() {
// use https://github.com/frakbot/Android-AccountChooser for
// compatibility with older devices
Intent intent = AccountManager.newChooseAccountIntent(null, null,
new String[] { "com.google" }, false, null, null, null, null);
startActivityForResult(intent, ACCOUNT_CODE);
}
private void requestToken() {
Account userAccount = null;
String user = authPreferences.getUser();
for (Account account : accountManager.getAccountsByType("com.google")) {
if (account.name.equals(user)) {
userAccount = account;
break;
}
}
accountManager.getAuthToken(userAccount, "oauth2:" + SCOPE, null, this,
new OnTokenAcquired(), null);
}
/**
* call this method if your token expired, or you want to request a new
* token for whatever reason. call requestToken() again afterwards in order
* to get a new token.
*/
private void invalidateToken() {
AccountManager accountManager = AccountManager.get(this);
accountManager.invalidateAuthToken("com.google",
authPreferences.getToken());
authPreferences.setToken(null);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == RESULT_OK) {
if (requestCode == AUTHORIZATION_CODE) {
requestToken();
} else if (requestCode == ACCOUNT_CODE) {
String accountName = data
.getStringExtra(AccountManager.KEY_ACCOUNT_NAME);
authPreferences.setUser(accountName);
// invalidate old tokens which might be cached. we want a fresh
// one, which is guaranteed to work
invalidateToken();
requestToken();
}
}
}
private class OnTokenAcquired implements AccountManagerCallback<Bundle> {
@Override
public void run(AccountManagerFuture<Bundle> result) {
try {
Bundle bundle = result.getResult();
Intent launch = (Intent) bundle.get(AccountManager.KEY_INTENT);
if (launch != null) {
startActivityForResult(launch, AUTHORIZATION_CODE);
} else {
String token = bundle
.getString(AccountManager.KEY_AUTHTOKEN);
authPreferences.setToken(token);
doCoolAuthenticatedStuff();
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
}
import android.content.Context;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
public class AuthPreferences {
private static final String KEY_USER = "user";
private static final String KEY_TOKEN = "token";
private SharedPreferences preferences;
public AuthPreferences(Context context) {
preferences = context
.getSharedPreferences("auth", Context.MODE_PRIVATE);
}
public void setUser(String user) {
Editor editor = preferences.edit();
editor.putString(KEY_USER, user);
editor.commit();
}
public void setToken(String password) {
Editor editor = preferences.edit();
editor.putString(KEY_TOKEN, password);
editor.commit();
}
public String getUser() {
return preferences.getString(KEY_USER, null);
}
public String getToken() {
return preferences.getString(KEY_TOKEN, null);
}
}
@nilk2311
Copy link

I have followed this code, however the result of accountManager.getAuthToken(userAccount, "oauth2:" + SCOPE, null, this,new OnTokenAcquired(), null) don't have any intent.
I'm a newbie.Do i have to setting anything to my project (like authencator or some elses?) and how to do it. Thanks!

@freak005
Copy link

Thanks a lot! Helped me from a great trouble.

@JamesSingleton
Copy link

JamesSingleton commented Aug 16, 2016

So I put the
if (authPreferences.getUser() != null && authPreferences.getToken() != null)

Inside a onClick and when I press Ok after selecting a gmail account, the app crashes. I am hoping to use this to do oAuth2 so any help would be greatly appreciated. The question can be found on StackOverflow here http://stackoverflow.com/questions/38968532/app-crashing-after-selecting-gmail-account-oauth2

@JamesSingleton
Copy link

JamesSingleton commented Aug 19, 2016

Joy... I revoked permission of my email to this code and now the permission dialog doesn't show anymore...I now get a BinderProxy error

@Ankhee
Copy link

Ankhee commented Feb 9, 2021

This gist helped me, thanks! I didn't know "oauth2:" is necessary at the beginning of scope.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment