1

It seems general consensus recommends storing authentication token in SharedPreferences, as this post suggests. However, I have a user object with several attributes, including an id, email, name, authentication token, and possibly more attributes. Should I store the authentication token ALONE in SharedPreferences and then for each activity, find the user by the authentication token:

String authenticationToken = User.findByAuthenticationToken(sharedPreferences.getString("authenticationToken"));

or should I convert the object to JSON and then store the entire user object in SharedPreferences? And then for each activity, deserialize it. This seems less efficient.

Community
  • 1
  • 1
Daniel Viglione
  • 8,014
  • 9
  • 67
  • 101

2 Answers2

2

You can store token in SharedPrefs, or use DI, as @Francesc said.

If you are using retrofit, I advice you to create singleton (or module) with retrofit instance, and add request interceptor to OkHttpClient.

 private OkHttpClient buildClient() {
    OkHttpClient.Builder builder = new OkHttpClient.Builder();

    //do any another stuff

    builder.addInterceptor(new RequestAuthInterceptor());

    return builder.build();
}


public static class RequestAuthInterceptor implements Interceptor {

    @Override
    public Response intercept(Chain chain) throws IOException {
        String jwtToken = SharedPrefs.getKeyJwt();
        if (jwtToken != null) {
            Request.Builder builder = chain.request().newBuilder();
            builder.addHeader("Authorization", jwtToken);
            return chain.proceed(builder.build());
        } else {
            return chain.proceed(chain.request());
        }
    }

}
Ufkoku
  • 2,384
  • 20
  • 44
0

Storing that data in preferences simply to pass it from one activity to another is inefficient. If you are using Dagger2 or any other dependency injection framework, you could consider having a User module that is created when the user logs in and holds the relevant user information. You can then access this module from your activities and read the user info.

If you're not using dependency injection you can do something similar with a Singleton class that you would populate when logging in and clear when logging out.

Edit: here are some extracts from one of my apps (this is in Kotlin)

Retrieving the token for API requests:

    val httpClientBuilder = OkHttpClient.Builder()
    if (BuildConfig.DEBUG) {
        val logging = HttpLoggingInterceptor()
        logging.level = HttpLoggingInterceptor.Level.BODY
        httpClientBuilder.addInterceptor(logging)
    }

    httpClientBuilder.addInterceptor { chain ->
        var request = chain.request()
        val token = ObjectGraphController.userComponent?.token
        token?.apply {
            request = request.newBuilder().addHeader("Session-Id", this).build()
        }
        chain.proceed(request)
    }

    val retrofit: Retrofit = Retrofit.Builder()
            .baseUrl(<YOUR ENDPOINT>)
            .addConverterFactory(GsonConverterFactory.create())
            .addCallAdapterFactory(RxJavaCallAdapterFactory.createWithScheduler(Schedulers.io()))
            .client(httpClientBuilder.build())
            .build()

User module:

@Module
class UserModule(val token: String) {
    @Provides
    @UserScope
    fun providesToken() = token
}

Set/clear component when logging in and out:

object ObjectGraphController {
    lateinit var objectGraph: ObjectGraph
    var userComponent: UserComponent? = null
        private set

    fun setUserComponent(token: String?) {
        if (token != null) {
            userComponent = objectGraph.userComponent(UserModule(token))
        } else {
            userComponent = null
        }
    }
}
Francesc
  • 25,014
  • 10
  • 66
  • 84
  • It's more than just passing from one activity to another. For each JSON API call, I will need to pass the authentication token. So it is beyond just passing to activities. – Daniel Viglione Mar 20 '17 at 21:29
  • Would you recommend using Dagger2 just for this purpose? To have a User model available across the app? People use Dagger2 for this purpose? – Daniel Viglione Mar 20 '17 at 21:32
  • Yes, I use a Dagger2 submodule that is instantiated when the user logs in, and that submodule is released when the user logs out. You can then query that data everywhere. You will obviously still need to persist whatever you need if you want to keep the user logged in after app restarts, but the point stands, you can keep the info in memory using a submodule or a Singleton instead of passing it around, which usually involves serialization and deserialization. – Francesc Mar 20 '17 at 21:44
  • Dagger2 is to Java/Android what Angular2 is to JavaScript? – Daniel Viglione Mar 20 '17 at 21:55
  • I'm not familiar with Angular2. Dagger2 is a Dependency Injection framework. It's particularly well suited to Android because it does not use reflection (so no speed penalties) and any issues show up at compile time as opposed to runtime. – Francesc Mar 20 '17 at 21:59
  • do you use Retrofit too? Common in the community to use both Dagger2 and Retrofit? They seem used together. – Daniel Viglione Apr 17 '17 at 20:26
  • Yes, I use Retrofit as you can see from the snippet above. – Francesc Apr 18 '17 at 23:07