Automatic cookie handling with OkHttp 3
Asked Answered
D

12

57

I am using okhttp 3.0.1.

Every where I am getting example for cookie handling that is with okhttp2

OkHttpClient client = new OkHttpClient();
CookieManager cookieManager = new CookieManager();
cookieManager.setCookiePolicy(CookiePolicy.ACCEPT_ALL);
client.setCookieHandler(cookieManager);

Can please some one guide me how to use in version 3. setCookieHandler method is not present in the version 3.

Dolph answered 19/1, 2016 at 16:19 Comment(1)
Some legacy stuff landed in my lap and I looked for how to do this with OkHttp 2. Your question is my answer. :-)Suborn
D
36

right now I'm playing with it. try PersistentCookieStore, add gradle dependencies for JavaNetCookieJar:

compile "com.squareup.okhttp3:okhttp-urlconnection:3.0.0-RC1"

and init

    // init cookie manager
    CookieHandler cookieHandler = new CookieManager(
            new PersistentCookieStore(ctx), CookiePolicy.ACCEPT_ALL);
    // init okhttp 3 logger
    HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
    logging.setLevel(HttpLoggingInterceptor.Level.BODY);
    // init OkHttpClient
    OkHttpClient httpClient = new OkHttpClient.Builder()
            .cookieJar(new JavaNetCookieJar(cookieHandler))
            .addInterceptor(logging)
            .build();

`

Diamonddiamondback answered 19/1, 2016 at 21:1 Comment(1)
FYI : In the near Future, they plan to remove the okhttp-urlconnection module. github.com/square/okhttp/blob/master/CHANGELOG.mdSnowber
P
70

If you want to use the new OkHttp 3 CookieJar and get rid of the okhttp-urlconnection dependency you can use this PersistentCookieJar.

You only need to create an instance of PersistentCookieJar and then just pass it to the OkHttp builder:

CookieJar cookieJar =
                    new PersistentCookieJar(new SetCookieCache(), new SharedPrefsCookiePersistor(context));

OkHttpClient okHttpClient = new OkHttpClient.Builder()
                    .cookieJar(cookieJar)
                    .build();
Palaeontography answered 11/2, 2016 at 17:46 Comment(10)
Much thanks for your approach. Works great for my purposes.Uzzi
Awesome buddy wasted 2 days for this... finally got it working with your approach. For those who are using retrofit2 use the jar instead of the persistancecookie store class.Flavia
@Palaeontography library is working fine but when we close app and going back to app it does not persist cookies and hence api got new cookies on very first call of web api. i have single instance of ur library and calling from Application class. Can u please tell me how to correct it?Overtrick
@AshuKumar probably it is due to your cookies not having expire date. This will make them session cookies and therefore they should not be persisted.Palaeontography
thanks for getting back to me. really thanks full... @franmontiel. my app requirement is do not let expire cookies, if cookies expire then session will not same and hence customer will logout automatically. can u sugesst me any solution or workaround, would be much better.Overtrick
how can i add new cookies when cookies going to expire ? @PalaeontographyOvertrick
@Palaeontography as app hit api then it getting cookies, and ur library saving cookies. for future api call, if we use php code to set cookies and send by api response then how i will able to save cookies to ur library for future api call ? or do u have better idea to achieve goal ? thanksOvertrick
Is there a way to explicitly get the value of the cookie? I can't find a way to do that.Agreeable
@Palaeontography wonderful buddy please can you add code on how to clear cookies ? I have added some details here :github.com/franmontiel/PersistentCookieJar/issues/12Hairless
It should be noted that the PersistentCookieJar project is distributed as an .aar. In other words, unless you are building for Android, you'll have to make some mods to use it.Dihedral
D
36

right now I'm playing with it. try PersistentCookieStore, add gradle dependencies for JavaNetCookieJar:

compile "com.squareup.okhttp3:okhttp-urlconnection:3.0.0-RC1"

and init

    // init cookie manager
    CookieHandler cookieHandler = new CookieManager(
            new PersistentCookieStore(ctx), CookiePolicy.ACCEPT_ALL);
    // init okhttp 3 logger
    HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
    logging.setLevel(HttpLoggingInterceptor.Level.BODY);
    // init OkHttpClient
    OkHttpClient httpClient = new OkHttpClient.Builder()
            .cookieJar(new JavaNetCookieJar(cookieHandler))
            .addInterceptor(logging)
            .build();

`

Diamonddiamondback answered 19/1, 2016 at 21:1 Comment(1)
FYI : In the near Future, they plan to remove the okhttp-urlconnection module. github.com/square/okhttp/blob/master/CHANGELOG.mdSnowber
H
32

Here you have a simple approach to create your own CookieJar. It can be extended as you wish. What I did is to implement a CookieJar and build the OkHttpClient using the OkHttpClient.Builder with this this CookieJar.

public class MyCookieJar implements CookieJar {

    private List<Cookie> cookies;

    @Override
    public void saveFromResponse(HttpUrl url, List<Cookie> cookies) {
        this.cookies =  cookies;
    }

    @Override
    public List<Cookie> loadForRequest(HttpUrl url) {
        if (cookies != null)
            return cookies;
        return new ArrayList<Cookie>();

    } 
}

Here is how you can create the OkHttpClient

OkHttpClient.Builder builder = new OkHttpClient.Builder();
builder.cookieJar(new MyCookieJar());
OkHttpClient client = builder.build();
Hescock answered 19/1, 2016 at 18:59 Comment(4)
This actually works great! My guess is that people complaining that it doesn't work don't realize they need to use the same instance of MyCookieJar throughout the app for cookies to work elsewhere.. Also they need to understand that cookies won't persist across app launches (once app is killed and memory released) since they're not being stored. For me this was perfect though.Counterword
Security warning: This CookieJar implementation sends all cookies to all sites. Never use it in production!Hepta
as vonox7 pointed this solution is a security abomination. xyman provided similar solution that sends cookies only for the given host: https://mcmap.net/q/190606/-automatic-cookie-handling-with-okhttp-3Ednaedny
How to get cookie value in other classDeputize
M
18

Adding compile "com.squareup.okhttp3:okhttp-urlconnection:3.8.1" to your build.gradle.

And then adding

 CookieManager cookieManager = new CookieManager();
 cookieManager.setCookiePolicy(CookiePolicy.ACCEPT_ALL);

 OkHttpClient defaultHttpClient = new OkHttpClient.Builder()
                                 .cookieJar(new JavaNetCookieJar(cookieManager))
                                 .build()

helped me without adding any third-party dependency except the one from OkHttp.

Maxson answered 29/10, 2017 at 5:34 Comment(2)
My previous method using github.com/franmontiel/PersistentCookieJar was failing with a one client's firewall. I used this method instead. It worked!Zhukov
Well done this is the solution I search for an hoursCesura
F
17

Here is working CookieJar implementation for OkHttp3. If you have multiple instances of OkHttp3 (usually you should have only one instance and use it as singletone) you should set the same instance of cookiejar to all of the http clients so they can share cookies !!! This implementation is not persisting cookies(they will all be discard on application restart) but it should be easy to implement SharedPreferences persistence instead of in-memory list of cookies(cookieStore).

    CookieJar cookieJar = new CookieJar() {
        private final HashMap<String, List<Cookie>> cookieStore = new HashMap<>();

        @Override
        public void saveFromResponse(HttpUrl url, List<Cookie> cookies) {
            cookieStore.put(url.host(), cookies);
        }

        @Override
        public List<Cookie> loadForRequest(HttpUrl url) {
            List<Cookie> cookies = cookieStore.get(url.host());
            return cookies != null ? cookies : new ArrayList<Cookie>();
        }
    };
    OkHttpClient httpClient = new OkHttpClient.Builder()
            .cookieJar(cookieJar)
            .build();
Fredelia answered 27/5, 2016 at 8:8 Comment(2)
it is important to note, that this solution only supports the most basic case: a site setting cookies for itself. 3rd party cookies for example will not work.Ednaedny
when storing the cookies at least use cookie.domain() to ensure they can be correctly read again.Welterweight
C
5

i used franmontiel PeristentCookieJar library for okhttp3 and retrofit.2. the benefit of this approach is : not need manipulate your okhttp request. Just set cookies or session when creating retrofit

1. first add this to your build.gradle(projectname)
 allprojects {
     repositories {
         jcenter()
         maven { url "https://jitpack.io" }
     }
 }
2. add this to your build.gradle
    compile 'com.github.franmontiel:PersistentCookieJar:v1.0.1'
3. build retrofit like this
public static Retrofit getClient(Context context) {

            ClearableCookieJar cookieJar = new PersistentCookieJar(new SetCookieCache(), new SharedPrefsCookiePersistor(context));
            OkHttpClient okHttpClient = new OkHttpClient.Builder()
                    .cookieJar(cookieJar)
                    .build();
            if (retrofit==null) {
                retrofit = new Retrofit.Builder()
                        .baseUrl(BASE_URL)
                        .addConverterFactory(GsonConverterFactory.create())
                        .client(okHttpClient)
                        .build();
            }
            return retrofit;
        }
Catchword answered 1/2, 2017 at 8:44 Comment(4)
But when i kill the App, than App need to login again mens we are not saving locally. Please let me out from this issue.Microsecond
@Microsecond I think you have 2 solutions: 1- you can save the results of login (for example in sharePrefrences) and then use it in next lunches. 2- calling your login in the background in each login (so you have to save login user information in sharePrefrences and call login by that). my mentioned library is useful to save cookies exactly like browsers. when you login for example on a website, then you can access all pages without login again.Catchword
How to save and store in SharedPrefence. I have just use following lines ClearableCookieJar cookieHandler = new PersistentCookieJar(new SetCookieCache(), new SharedPrefsCookiePersistor(context)); HttpLoggingInterceptor logging = new HttpLoggingInterceptor(); logging.setLevel(HttpLoggingInterceptor.Level.BODY); OkHttpClient httpClient = new OkHttpClient.Builder() .cookieJar(cookieHandler) .addInterceptor(logging) .build();Microsecond
I have handled with the help of first option but when i try to call any other API then I need to forcefully logout from app and than login because retrofit changed the PHPSESSIONID and defalut cookies also.Microsecond
T
4

You can try it in Kotlin:

val cookieJar = JavaNetCookieJar(CookieManager())
val url = "https://www.google.com/"

val requestBuilder = Request
        .Builder()
        .url(url)
        .get()

val request = requestBuilder
        .build()

val response = OkHttpClient.Builder()
        .cookieJar(cookieJar)
        .build()
        .newCall(request)
        .execute()

Gradle

dependencies {
    implementation("com.squareup.okhttp3:okhttp:4.2.2")
    implementation("com.squareup.okhttp3:okhttp-urlconnection:4.2.2")
}
Tallent answered 20/3, 2020 at 14:24 Comment(0)
F
2

minimal solution that persists cookie after first run

public class SharedPrefCookieJar implements CookieJar {

    Map<String, Cookie> cookieMap = new HashMap();
    private Context mContext;
    private SharedPrefsManager mSharedPrefsManager;

    @Inject
    public SharedPrefCookieJar(Context context, SharedPrefsManager sharedPrefsManager) {
        mContext = context;
        mSharedPrefsManager = sharedPrefsManager;
        cookieMap = sharedPrefsManager.getCookieMap(context);
        if (cookieMap == null) {
            cookieMap = new HashMap<>();
        }
    }

    @Override
    public void saveFromResponse(HttpUrl url, List<Cookie> cookies) {

        for (Cookie cookie : cookies) {
            cookieMap.put(cookie.name(), cookie);
        }
        mSharedPrefsManager.setCookieMap(mContext, cookieMap);
    }

    @Override
    public List<Cookie> loadForRequest(HttpUrl url) {
        List<Cookie> validCookies = new ArrayList<>();
        for (Map.Entry<String, Cookie> entry : cookieMap.entrySet()) {
            Cookie cookie = entry.getValue();
            if (cookie.expiresAt() < System.currentTimeMillis()) {

            } else {
                validCookies.add(cookie);
            }
        }
        return validCookies;
    }

}

with dagger

@Module
public class ApiModule {


    @Provides
    @Singleton
    InstagramService provideInstagramService(OkHttpClient client)
    {
        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl(InstagramService.BASE_URL)
                .client(client)
                .addConverterFactory(GsonConverterFactory.create())
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                .build();
        InstagramService instagramService = retrofit.create(InstagramService.class);
        return instagramService;
    }


    @Provides
    @Singleton
    OkHttpClient provideOkHttpClient(SharedPrefCookieJar sharedPrefCookieJar){
        OkHttpClient client;
        OkHttpClient.Builder builder = new OkHttpClient.Builder();
        if(BuildConfig.DEBUG)
        {
            HttpLoggingInterceptor httpLoggingInterceptor = new HttpLoggingInterceptor();
            httpLoggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
            builder
                .addInterceptor(httpLoggingInterceptor)
                .addInterceptor(new InstagramHeaderInterceptor())
                .addNetworkInterceptor(new LoggingInterceptor());

        }
        client = builder.cookieJar(sharedPrefCookieJar).build();
        return client;
    }
}
Fraction answered 6/12, 2017 at 21:55 Comment(0)
C
0

I used @gncabrera's solution but also created a helper class to help with initialization and also to make it easy to share a CookieJar across the application.

public class OkHttpClientCreator {

    private static CookieJar mCookieJar;

    public static OkHttpClient.Builder getNewHttpClientBuilder(boolean isDebug, boolean useCookies) {
        if (mCookieJar == null && useCookies) {
            mCookieJar = new BasicCookieJar();
        }
        OkHttpClient.Builder builder = new OkHttpClient.Builder();
        if (useCookies) {
            builder.cookieJar(mCookieJar);
        }
        if (isDebug) {
            builder.addInterceptor(new LoggingInterceptor());
        }
        return builder;
    }

    public static OkHttpClient getNewHttpClient(boolean isDebug, boolean useCookies) {
       return getNewHttpClientBuilder(isDebug, useCookies).build();
    }

}

The logging interceptor is used in debug mode to print out request information and the cookie jar instance is shared. across callers so that if requests need to use a common cookie handler they can. These cookies won't persist across app launches but that's not a requirement for my application since we use token based sessions and the only need for cookies is the short time between logging in and generating the token.

Note: BasicCookieJar is just the same implementation as gncabrera's MyCookieJar

Counterword answered 22/4, 2016 at 22:33 Comment(0)
A
0

Add implementation "com.squareup.okhttp3:okhttp-urlconnection:3.8.1" into your build.gradle.

var interceptor = HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY)
var cookieHandler: CookieHandler = CookieManager()

private var retrofit: Retrofit? = null
retrofit = Retrofit.Builder()
                        .baseUrl(BASE_URL)
                        .client(client)
                        .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
                        .build()

private val client : OkHttpClient
            private get() {
                val builder = OkHttpClient.Builder()
                builder.addNetworkInterceptor(interceptor)
                builder.cookieJar(JavaNetCookieJar(cookieHandler))
                builder.connectTimeout(15, TimeUnit.SECONDS)
                builder.readTimeout(20, TimeUnit.SECONDS)
                builder.writeTimeout(20, TimeUnit.SECONDS)
                builder.retryOnConnectionFailure(true)
                return builder.build()
            }
Asia answered 16/5, 2020 at 19:13 Comment(0)
S
0

if you use Kotlin with dagger or hilt and you inject your Okhttp, you can add

implementation 'com.squareup.okhttp3:okhttp-urlconnection:4.9.0'

I feel the version should be the same as your okhttpclient version.

@Provides
@Singleton
fun providesOkHTTPClient(application: Application): OkHttpClient {
    val cookieManager = CookieManager()
    cookieManager.setCookiePolicy(CookiePolicy.ACCEPT_ALL)
    
    return OkHttpClient.Builder()
        .cookieJar(JavaNetCookieJar(cookieManager))
        .addInterceptor(
            ChuckInterceptor(application)
                .showNotification(true)
                .retainDataFor(ChuckInterceptor.Period.ONE_DAY)
        ).addInterceptor(
            HttpLoggingInterceptor().setLevel(
                if (BuildConfig.DEBUG) HttpLoggingInterceptor.Level.BODY
                else HttpLoggingInterceptor.Level.NONE
            )
        ).build()
}

remember to add the dependency on the same module (data) where you are providing okhttpClient

Spelt answered 6/9, 2021 at 22:56 Comment(0)
W
-1

I can show you a library for letting OkHttp3 handle cookies automatically. It can be used easily.

Just Keep cookies on memory, to do persistence yourself if you need. Run on Android and Pure Java environment.

    String url = "https://example.com/webapi";

    OkHttp3CookieHelper cookieHelper = new OkHttp3CookieHelper();

    OkHttpClient client = new OkHttpClient.Builder()
            .cookieJar(cookieHelper.cookieJar())
            .build();

    Request request = new Request.Builder()
            .url(url)
            .build();

Gradle

compile 'org.riversun:okhttp3-cookie-helper:1.0.0'

Maven

<dependency>
<groupId>org.riversun</groupId>
<artifactId>okhttp3-cookie-helper</artifactId>
<version>1.0.0</version>
</dependency>
Wither answered 25/3, 2017 at 9:55 Comment(2)
This isn't storing the cookie using the domain from the cookie itself - so this won't work that great.Welterweight
I mentioned above.Wither

© 2022 - 2024 — McMap. All rights reserved.