coost is a persistent cookie storage module that simplifies storing and recreating cookie jar between app sessions. coost requires minimal configuration and supports (manual) importing existing session cookies from a browser.
Adding coost module to your Go app: go get github.com/boggydigital/coost
A typical coost flow in a client app looks like this:
- Create new (persistent) cookie jar;
- Defer storing cookies to update any new values we got from the server;
- Get *http.Client from that (persistent) cookie jar;
- (use this client anywhere in the app where you'd expect cookies will be used).
More details on each step are provided below.
In order to create a new (persistent) cookie jar you need to provide two pieces of information:
- Slice of hosts for the jar - e.g.
[]string {"example.com"}
; - Directory to store the jar - e.g.
""
, that will represent process working directory.
Clients need to call jar, err := coost.NewJar(hosts, directory)
and would get a pointer to a jar
object that can be used to get an http.Client
instance as well as Store
that jar.
During application lifecycle, cookie jar can get updated with new cookie values from the server. To
persist those values jar provides a Store
method.
Typically, clients would add defer jar.Store()
after initializing the jar. NOTE: this would ignore
any errors that can happen during saving cookies file to the storage.
An extended form of the same call that would allow handling errors would be:
defer func (jar coost.PersistentCookieJar) {
if err := jar.Store(); err != nil {
//handle error
}
}(jar)
Following jar initialization, clients can call jar.NewClient()
convenience method to get a pointer
to an http.Client
instance using that jar. Please note, that this convenience method sets some
default timeouts for the http.Client
instance.
Alternatively, clients can use the jar they got as a result of NewJar
method in their
own http.Client
instance.
Please note that cookies file created by coost is not encrypted or obfuscated in any way. This is by design.
cookies.txt
is a trivial text structure that stores space indented cookie name value pairs by hosts:
host1
cookie1=cookie1_value
cookie2=cookie2_value
host2
cookie1=cookie1_value
coost is agnostic to the authentication model used by the service. Some common scenarios using cookies:
- Application handles authentication and provides prompt for username, password, 2FA, etc. Server sets response cookies that are then persisted by coost and users won't need to re-authenticate on every application session;
- Users copy session cookies from an existing browser session.
Both scenarios are detailed below.
Detailing full authentication flow is out of the scope for this document and most likely would be application specific. There are few callouts that would be helpful to clients:
- Make sure you're using
http.Client
with a cookie jar initialized by coost for every authentication related request in order to get (potentially updated) response cookies; - Make sure to
Store
the jar when meaningful changes happen (e.g. when the authentication flow completes).
In certain scenarios it might not be practical to implement a full authentication flow - for example for headless services that don't expect or allow user input.
To support those scenarios coost provides a way to import existing browser session cookies. Here is how to do that:
- (all instructions below are using Google Chrome as the browser, though it should generally work with any browser);
- Launch a browser, then open Developer Tools:
- Select "Customize and control Google Chrome" menu item, visually represented as three vertical dots;
- Select "More Tools" menu item, then "Developer Tools";
- Select "Network" tab in the Developer Tools.
- Navigate to the desired website (e.g.
example.com
); - Select that navigation request in the Network tab of Developer Tools;
- Select "Headers" tab in the request preview section;
- Navigate to the
Request Headers
section (notResponse Headers
!); - Find
cookie:
header andCopy value
for that header; - Open (or create)
cookies.txt
for the client application, update (or create) a new section for the host in question (e.g.example.com
); - In that host section add new key
cookie-header
and paste the copied value in quotes:
example.com
cookie-header=<paste-copied-value-here>
- (Repeat steps 2-8 for any additional hosts that client application might require).
Some tips you can use to verify cookie-header
has been imported correctly:
- Cookie values are presented as
;
separated key value pairs, where key and value are separated with=
. Example:
COOKIE1=cookie-value1; COOKIE2=cookie-value2
cookie-header
should be the only name value pair under a host, since it'll replace any other values;- Split
cookie-header
values are stored as separate values afterStore
method is invoked, so effectivelycookie-header
is only imported, never persisted. If you see it after callingStore
- something is wrong.
coost has been designed as a thin wrapper on top of Go runtime http.CookieJar
and has two main points of
interest:
- Restoring cookies into a jar
- Storing cookie jar
Both steps involve working with local storage, and clients should anticipate errors typical for general storage operations. Working with cookies themselves is handled by Go language runtime.
Expectations and common problems to check for:
- File should be located where the application expects it to be. When using
""
make sure the file is in the current app working directory at the moment ofNewJar
method call. When using specific directory make sure the file is present at this location and is accessible to the app; - Only the hosts specified for the
NewJar
method call are used to populate cookie jar, regardless of what hosts are present incookie.txt
. This is by design; http.Client
with the jar is used for requests. Just loading the cookies into the jar does nothing - it's only useful, when called through anhttp.Client
with that jar.
Expectations and common problems to check for:
- File would be stored relative to the current app working directory at the time of the invocation. When using specific directory make sure it's accessible to the app;
- Only the hosts specified at the
NewJar
method call will be updated with new cookie values. This is by design.
coost has been tactically instrumented with github.com/boggydigital/nod
logging calls, and clients
might find enabling nod logging output to be helpful. Please check github.com/boggydigital/nod
for
more details.