Usar token de renovación si el token de autenticación expiró en el autenticador de cuenta

Tengo una aplicación que utiliza AccountManager para almacenar las cuentas de los usuarios. Los usuarios inician sesión y se registran a través de mi API REST utilizando OAuth2.0 password-username credentials flow.

Los tokens de acceso que reciben los usuarios caducan en 2 horas y necesitan ser actualizados hasta que expiren de nuevo, y así sucesivamente.

Necesito implementar esta funcionalidad de actualización en mi autenticador.

Tengo un modelo llamado AccessToken que tiene los campos siguientes:

String accessToken, String tokenType, Long expiresIn, String refreshToken, String scope, Long createdAt .

Así que actualmente, en mi método getAuthToken en la clase AccountAuthenticator , recibo este objeto AccessToken y uso su campo accessToken como un Auth Token para mi Account Manager.

Lo que necesito es guardar de alguna manera el token de actualización y el token de autenticación con mi administrador de cuentas y cuando la aplicación intenta acceder a la API y recibe la respuesta de error: {"error": "access token expired"} para actualizar el token de acceso actual Utilizando la cadena AccessToken objeto AccessToken recibido anteriormente. Sin embargo, no estoy seguro de cómo debo hacerlo.

Mi método getAuthToken en la clase de autenticador se ve actualmente así:

 @Override public Bundle getAuthToken(AccountAuthenticatorResponse accountAuthenticatorResponse, Account account, String authTokenType, Bundle options) throws NetworkErrorException { if (!authTokenType.equals(AccountGeneral.AUTHTOKEN_TYPE_READ_ONLY) && !authTokenType.equals(AccountGeneral.AUTHTOKEN_TYPE_FULL_ACCESS)) { final Bundle result = new Bundle(); result.putString(AccountManager.KEY_ERROR_MESSAGE, "Invalid authTokenType"); return result; } final AccountManager manager = AccountManager.get(context.getApplicationContext()); String authToken = manager.peekAuthToken(account, authTokenType); Log.d("Discounty", TAG + " > peekAuthToken returned - " + authToken); if (TextUtils.isEmpty(authToken)) { final String password = manager.getPassword(account); if (password != null) { try { authToken = discountyService.getAccessToken(DiscountyService.ACCESS_GRANT_TYPE, account.name, password).toBlocking().first().getAccessToken(); // ======= // Here the above discountyService.getAccessToken(...) call returns // AccessToken object on which I call the .getAccessToken() // getter which returns a string. // ======= } catch (Exception e) { e.printStackTrace(); } } } if (!TextUtils.isEmpty(authToken)) { final Bundle result = new Bundle(); result.putString(AccountManager.KEY_ACCOUNT_NAME, account.name); result.putString(AccountManager.KEY_ACCOUNT_TYPE, account.type); result.putString(AccountManager.KEY_AUTHTOKEN, authToken); return result; } final Intent intent = new Intent(context, LoginActivity.class); intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, accountAuthenticatorResponse); intent.putExtra(LoginActivity.ARG_ACCOUNT_TYPE, account.type); intent.putExtra(LoginActivity.ARG_AUTH_TYPE, authTokenType); final Bundle bundle = new Bundle(); bundle.putParcelable(AccountManager.KEY_INTENT, intent); return bundle; } 

Y la clase AccountGeneral sólo contiene algunas constantes:

 public class AccountGeneral { public static final String ACCOUNT_TYPE = "com.discounty"; public static final String ACCOUNT_NAME = "Discounty"; public static final String AUTHTOKEN_TYPE_READ_ONLY = "Read only"; public static final String AUTHTOKE_TYPE_READ_ONLY_LABEL = "Read only access to a Discounty account"; public static final String AUTHTOKEN_TYPE_FULL_ACCESS = "Full access"; public static final String AUTHTOKEN_TYPE_FULL_ACCESS_LABEL = "Full access to a Discounty account"; } 

La aplicación también utilizará SyncAdapter e interactuará con la API con bastante frecuencia para sincronizar los datos desde y hacia el servidor, y estas llamadas a la API también necesitarán usar tokens de acceso como parámetros en las solicitudes, así que realmente necesito implementar esta actualización Funcionalidad y hacerlo automático.


¿Alguien sabe cómo implementarlo correctamente?


PS: Estaré usando una base de datos local para almacenar todos mis datos y también podría almacenar los objetos token. Esto parece un hack fácil, aunque inseguro. Tal vez debería almacenar sólo un token de actualización a la vez como un registro de db y actualizarlo como la aplicación recibe el nuevo token?

PPS: Soy libre de cambiar la forma en que funciona la API de todos modos, así que si hay sugerencias sobre cómo mejorar la aplicación para móviles, mejorando la API, también serán muy apreciados.

Puede guardar el token de actualización en los datos de usuario de su cuenta cuando agregue su cuenta por primera vez usando:

 Bundle userdata = new Bundle; userdata.putString("refreshToken", refreshToken); mAccountManager.addAccountExplicitly (account, password, userdata); 

También puede configurar los userdata después de agregar la cuenta llamando a:

 mAccountManager.setUserData(account, "refreshToken", refreshToken); 

Cuando acceda a token expirado, puede recuperar su token de actualización llamando a:

 String refreshToken = mAccountManager.getUserData(account, "refreshToken"); 

Utilice refreshToken para recuperar un nuevo token de acceso.

  • Javax.mail.AuthenticationFailedException en Android
  • Firebase y el nuevo inicio de sesión de Google en Android
  • HttpURLConnection funcionó bien en Android 2.x pero NO en 4.1: no se encontraron desafíos de autenticación
  • Leer / escribir en etiqueta NFC con protección por contraseña
  • Consumir sitio WebAPI2 desde un cliente Android con autenticación de Google
  • ¿Existe ya una biblioteca OAuth2 para Java / Android?
  • Autenticador Okhttp multihilo
  • Preguntas de inicio de Android HTTP
  • Librería / marco apropiado de Oauth2 del androide
  • Cómo implementar AccountManager en mi aplicación
  • Mantenimiento de cookies entre las solicitudes HTTP enviadas por Android Apps
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.