Use this file to discover all available pages before exploring further.
This document is part of the Mobile + API Architecture Scenario and it explains how to implement the mobile application in Android. Please refer to the scenario for information on the implemented solution.
The LoginActivity will handle user authorization and be the initial screen users see. We’ll create a login() method to initialize a WebAuthProvider and start authentication. Ensure you provide the correct scheme, , and scope to the WebAuthProvider. For this implementation we will use:
scheme: demo
audience: https://api.exampleco.com/timesheets (the Node.JS API)
response_type: code
scope: create:timesheets read:timesheets openid profile email offline_access. These scopes will enable us to POST and GET to the Node.JS API, as well as retrieve the user profile and a .
To store the credentials received after login, we’ll use the CredentialsManager from the Auth0.Android library and SharedPreferences for storage.Before initializing the WebAuthProvider in the login() method, we can create the CredentialsManager. Passing an AuthenticationAPIClient to the CredentialsManager enables it to refresh the if they are expired.
private void login() { Auth0 auth0 = new Auth0(getString(R.string.auth0_client_id), getString(R.string.auth0_domain)); auth0.setOIDCConformant(true); AuthenticationAPIClient authAPIClient = new AuthenticationAPIClient(auth0); SharedPreferencesStorage sharedPrefStorage = new SharedPreferencesStorage(this); final CredentialsManager credentialsManager = new CredentialsManager(authAPIClient, sharedPrefStorage); WebAuthProvider.init(auth0) // ... }
Now update the login() method so that credentials are stored via the CredentialsManager after a successful authentication.
// ...@Overridepublic void onSuccess(@NonNull final Credentials credentials) { runOnUiThread(new Runnable() { @Override public void run() { Toast.makeText(LoginActivity.this, "Log In - Success", Toast.LENGTH_SHORT).show(); } }); credentialsManager.saveCredentials(credentials); startActivity(new Intent(LoginActivity.this, TimeSheetActivity.class));// ...}
To handle storing user profile information we’ll create a manager class UserProfileManager. The UserProfileManager will use SharedPreferences to store data.
package com.auth0.samples.utils;import android.content.Context;import android.content.SharedPreferences;import com.auth0.android.result.UserProfile;import com.auth0.samples.models.User;public class UserProfileManager { private static final String PREFERENCES_NAME = "auth0_user_profile"; private static final String EMAIL = "email"; private static final String NAME = "name"; private static final String PICTURE_URL = "picture_url"; public static void saveUserInfo(Context context, User userInfo) { SharedPreferences sp = context.getSharedPreferences( PREFERENCES_NAME, Context.MODE_PRIVATE); sp.edit() .putString(EMAIL, userInfo.getEmail()) .putString(NAME, userInfo.getName()) .putString(PICTURE_URL, userInfo.getPictureURL()) .apply(); } public static User getUserInfo(Context context) { SharedPreferences sp = context.getSharedPreferences( PREFERENCES_NAME, Context.MODE_PRIVATE); return new User( sp.getString(EMAIL, null), sp.getString(NAME, null), sp.getString(PICTURE_URL, null) ); } public static void deleteUserInfo(Context context) { SharedPreferences sp = context.getSharedPreferences( PREFERENCES_NAME, Context.MODE_PRIVATE); sp.edit() .putString(EMAIL, null) .putString(NAME, null) .putString(PICTURE_URL, null) .apply(); }}
Next, update the login() method in the LoginActivity to retrieve the and get the user profile from the token with the JWTDecode.Android library. Then store the user profile with the UserProfileManager.
// ...@Overridepublic void onSuccess(@NonNull final Credentials credentials) { runOnUiThread(new Runnable() { @Override public void run() { Toast.makeText(LoginActivity.this, "Log In - Success", Toast.LENGTH_SHORT).show(); } }); credentialsManager.saveCredentials(credentials); JWT jwt = new JWT(credentials.getIdToken()); User user = new User( jwt.getClaim("email").asString(), jwt.getClaim("name").asString(), jwt.getClaim("picture").asString() ); UserProfileManager.saveUserInfo(LoginActivity.this, user); startActivity(new Intent(LoginActivity.this, TimeSheetActivity.class));}// ...
Step 4. Display UI Elements Conditionally Based on Scope
To determine whether a user has permissions to perform certain actions, we can look at the scope that was granted to the user during the authentication process. The scope will contain a string with all the scopes granted to a user, so to determine whether a particular scope was granted, we simply need to look whether the string of scopes contain the substring for that particular scope.
First, we can update the User class to store the granted scopes, and then provide a helper method, hasScope() which can be used to determine whether the granted scopes contain a particular scope:
public class User { private String email; private String name; private String pictureURL; private String grantedScope; public User(String email, String name, String pictureURL, String grantedScope) { this.email = email; this.name = name; this.pictureURL = pictureURL; this.grantedScope = grantedScope; } public String getEmail() { return email; } public String getGrantedScope() { return grantedScope; } public String getName() { return name; } public String getPictureURL() { return pictureURL; } public Boolean hasScope(String scope) { return grantedScope.contains(scope); }}
Also remember to update the UserProfileManager to store the extra field:
public class UserProfileManager { private static final String PREFERENCES_NAME = "auth0_user_profile"; private static final String EMAIL = "email"; private static final String NAME = "name"; private static final String PICTURE_URL = "picture_url"; private static final String SCOPE = "scope"; public static void saveUserInfo(Context context, User userInfo) { SharedPreferences sp = context.getSharedPreferences( PREFERENCES_NAME, Context.MODE_PRIVATE); sp.edit() .putString(EMAIL, userInfo.getEmail()) .putString(NAME, userInfo.getName()) .putString(PICTURE_URL, userInfo.getPictureURL()) .putString(SCOPE, userInfo.getGrantedScope()) .apply(); } public static User getUserInfo(Context context) { SharedPreferences sp = context.getSharedPreferences( PREFERENCES_NAME, Context.MODE_PRIVATE); return new User( sp.getString(EMAIL, null), sp.getString(NAME, null), sp.getString(PICTURE_URL, null), sp.getString(SCOPE, null) ); } public static void deleteUserInfo(Context context) { SharedPreferences sp = context.getSharedPreferences( PREFERENCES_NAME, Context.MODE_PRIVATE); sp.edit() .putString(EMAIL, null) .putString(NAME, null) .putString(PICTURE_URL, null) .putString(SCOPE, null) .apply(); }}
Next, update the LoginActivity to pass along the scope so it can be stored in the User object:
// ...@Overridepublic void onSuccess(@NonNull final Credentials credentials) { runOnUiThread(new Runnable() { @Override public void run() { Toast.makeText(LoginActivity.this, "Log In - Success", Toast.LENGTH_SHORT).show(); } }); credentialsManager.saveCredentials(credentials); JWT jwt = new JWT(credentials.getIdToken()); String scopes = credentials.getScope(); User user = new User( jwt.getClaim("email").asString(), jwt.getClaim("name").asString(), jwt.getClaim("picture").asString(), credentials.getScope() ); UserProfileManager.saveUserInfo(LoginActivity.this, user); startActivity(new Intent(LoginActivity.this, TimeSheetActivity.class));}// ...
Now, we can display certain UI elements based on whether the user was granted a particular scope. As an example, we have an approval menu item which should only be visible to users who have been granted the approve:timesheets scope.Below you can see the code from the BaseActivity class which checks whether a user has the approve:timesheets scope, and based on that will set the visibility of the menu item which displays the approval activity:
To display the logged in user’s profile we’ll create the UserActivity, a corresponding user_activity.xml layout, and the user_action_menu.xml for the Toolbar navigation. The view will display the user’s name, email, and profile picture.
In the onCreate() method we’ll retrieve the user information from the UserProfileManager and set the values in the view. As before, the onCreateOptionsMenu() and onOptionsItemSelected() methods handle the Toolbar widget navigation functionality.
package com.auth0.samples.activities;import android.app.Activity;import android.content.Intent;import android.os.Bundle;import android.support.annotation.Nullable;import android.support.v7.app.AppCompatActivity;import android.support.v7.widget.Toolbar;import android.view.Menu;import android.view.MenuInflater;import android.view.MenuItem;import android.widget.ImageView;import android.widget.TextView;import com.auth0.samples.R;import com.auth0.samples.utils.ImageTask;import com.auth0.samples.utils.UserProfileManager;public class UserActivity extends AppCompatActivity { @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.user_activity); Toolbar navToolbar = (Toolbar) findViewById(R.id.navToolbar); setSupportActionBar(navToolbar); TextView tvName = (TextView) findViewById(R.id.tvName); TextView tvEmail = (TextView) findViewById(R.id.tvEmail); tvName.setText(UserProfileManager.getUserInfo(this).getName()); tvEmail.setText(UserProfileManager.getUserInfo(this).getEmail()); new ImageTask((ImageView) findViewById(R.id.ivPicture)) .execute(UserProfileManager.getUserInfo(this).getPictureURL()); UserProfileManager.getUserInfo(this).getName(); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu items for use in the action bar MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.user_action_menu, menu); return super.onCreateOptionsMenu(menu); } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.action_new: startActivity(new Intent(UserActivity.this, FormActivity.class)); break; case R.id.action_view: startActivity(new Intent(UserActivity.this, TimeSheetActivity.class)); break; default: // If we got here, the user's action was not recognized. // Invoke the superclass to handle it. return super.onOptionsItemSelected(item); } return true; }}