Cookies

Cookies is an important, built-in request guard: it allows you to get, set, and remove cookies. Because Cookies is a request guard, an argument of its type can simply be added to a handler:

  1. use rocket::http::Cookies;
  2. #[get("/")]
  3. fn index(cookies: Cookies) -> Option<String> {
  4. cookies.get("message")
  5. .map(|value| format!("Message: {}", value))
  6. }

This results in the incoming request’s cookies being accessible from the handler. The example above retrieves a cookie named message. Cookies can also be set and removed using the Cookies guard. The cookies example on GitHub illustrates further use of the Cookies type to get and set cookies, while the Cookies documentation contains complete usage information.

Private Cookies

Cookies added via the Cookies::add() method are set in the clear. In other words, the value set is visible by the client. For sensitive data, Rocket provides private cookies.

Private cookies are just like regular cookies except that they are encrypted using authenticated encryption, a form of encryption which simultaneously provides confidentiality, integrity, and authenticity. This means that private cookies cannot be inspected, tampered with, or manufactured by clients. If you prefer, you can think of private cookies as being signed and encrypted.

The API for retrieving, adding, and removing private cookies is identical except methods are suffixed with _private. These methods are: get_private, add_private, and remove_private. An example of their usage is below:

  1. /// Retrieve the user's ID, if any.
  2. #[get("/user_id")]
  3. fn user_id(cookies: Cookies) -> Option<String> {
  4. cookies.get_private("user_id")
  5. .map(|cookie| format!("User ID: {}", cookie.value()))
  6. }
  7. /// Remove the `user_id` cookie.
  8. #[post("/logout")]
  9. fn logout(mut cookies: Cookies) -> Flash<Redirect> {
  10. cookies.remove_private(Cookie::named("user_id"));
  11. Flash::success(Redirect::to("/"), "Successfully logged out.")
  12. }

Secret Key

To encrypt private cookies, Rocket uses the 256-bit key specified in the secret_key configuration parameter. If one is not specified, Rocket will automatically generate a fresh key. Note, however, that a private cookie can only be decrypted with the same key with which it was encrypted. As such, it is important to set a secret_key configuration parameter when using private cookies so that cookies decrypt properly after an application restart. Rocket emits a warning if an application is run in production without a configured secret_key.

Generating a string suitable for use as a secret_key configuration value is usually done through tools like openssl. Using openssl, a 256-bit base64 key can be generated with the command openssl rand -base64 32.

For more information on configuration, see the Configuration section of the guide.

One-At-A-Time

For safety reasons, Rocket currently requires that at most one Cookies instance be active at a time. It’s uncommon to run into this restriction, but it can be confusing to handle if it does crop up.

If this does happen, Rocket will emit messages to the console that look as follows:

  1. => Error: Multiple `Cookies` instances are active at once.
  2. => An instance of `Cookies` must be dropped before another can be retrieved.
  3. => Warning: The retrieved `Cookies` instance will be empty.

The messages will be emitted when a violating handler is called. The issue can be resolved by ensuring that two instances of Cookies cannot be active at once due to the offending handler. A common error is to have a handler that uses a Cookies request guard as well as a Custom request guard that retrieves Cookies, as so:

  1. #[get("/")]
  2. fn bad(cookies: Cookies, custom: Custom) { .. }

Because the cookies guard will fire before the custom guard, the custom guard will retrieve an instance of Cookies when one already exists for cookies. This scenario can be fixed by simply swapping the order of the guards:

  1. #[get("/")]
  2. fn good(custom: Custom, cookies: Cookies) { .. }