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.

spiegelm
  • 65
  • 7
user2672763
  • 801
  • 1
  • 9
  • 18

12 Answers12

68

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();
franmontiel
  • 1,860
  • 1
  • 16
  • 20
  • Much thanks for your approach. Works great for my purposes. – veinhorn Apr 03 '16 at 14:14
  • 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. – Manikanta Jul 04 '16 at 09:33
  • 1
    @franmontiel 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? – Ashu Kumar May 18 '17 at 07:10
  • @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. – franmontiel May 18 '17 at 12:32
  • 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. – Ashu Kumar May 19 '17 at 07:54
  • how can i add new cookies when cookies going to expire ? @franmontiel – Ashu Kumar May 19 '17 at 07:55
  • @franmontiel 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 ? thanks – Ashu Kumar May 19 '17 at 11:58
  • Is there a way to explicitly get the value of the cookie? I can't find a way to do that. – Antonis Sep 12 '17 at 08:12
  • @franmontiel wonderful buddy please can you add code on how to clear cookies ? I have added some details here :https://github.com/franmontiel/PersistentCookieJar/issues/12 – manjunath kallannavar May 28 '18 at 12:51
  • 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. – CMerrill Apr 03 '21 at 02:03
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();

`

1f7
  • 575
  • 4
  • 11
  • 6
    FYI : In the near Future, they plan to remove the okhttp-urlconnection module. github.com/square/okhttp/blob/master/CHANGELOG.md – Tobliug Apr 12 '16 at 19:11
28

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();
gncabrera
  • 595
  • 6
  • 10
  • 5
    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. – Matt Wolfe Apr 22 '16 at 22:28
  • 23
    Security warning: This CookieJar implementation sends all cookies to all sites. Never use it in production! – vonox7 Oct 12 '16 at 20:31
  • 2
    as vonox7 pointed this solution is a security abomination. xyman provided similar solution that sends cookies only for the given host: http://stackoverflow.com/a/37478166/1220560 – morgwai Jan 06 '17 at 12:48
  • How to get cookie value in other class – Akash kumar Apr 08 '20 at 10:37
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.

Shubham
  • 2,627
  • 3
  • 20
  • 36
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();
xyman
  • 399
  • 3
  • 10
  • 1
    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. – morgwai Jan 09 '17 at 05:17
  • 2
    when storing the cookies at least use cookie.domain() to ensure they can be correctly read again. – slott Apr 12 '17 at 21:31
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;
        }
HDE 226868
  • 111
  • 1
  • 4
  • 7
iman kazemayni
  • 1,255
  • 1
  • 19
  • 20
  • 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. – Peter Sep 07 '18 at 13:26
  • 1
    @Peter 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. – iman kazemayni Sep 08 '18 at 08:35
  • 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(); – Peter Sep 08 '18 at 11:20
  • 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. – Peter Sep 08 '18 at 11:58
3

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")
}
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;
    }
}
Vihaan Verma
  • 12,815
  • 19
  • 97
  • 126
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

Matt Wolfe
  • 8,924
  • 8
  • 60
  • 77
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()
            }
Sayan Manna
  • 584
  • 7
  • 13
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

-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>
riversun
  • 758
  • 8
  • 12