Repository: phoenixframework/phoenix (elixir)

Issue:
Allow silencing Phoenix.Token warning
### Environment

* Elixir version (elixir -v): 1.7.0-dev (c42df09f3)
* Phoenix version (mix deps): 1.3.0

### Expected behavior

We're stuck for some time having to support tokens issued with `Phoenix.Token` with an infinite expiration timeout. I understand the reasoning behind the warning in [`Phoenix.Token.verify/4`](https://github.com/phoenixframework/phoenix/blob/master/lib/phoenix/token.ex#L179) perfectly, it's unfortunately very annoying when I can't do much about it.

It would be great, if there was a way to silence the warning - I propose passing `max_age: :infinity` as an explicit way to opt-out from the token age checking. This should be the least disruptive and should make sure that the person using it understands the trade-offs.

### Actual behavior

We're spammed with the warnings, since they are issued at runtime.


Pull request description:
Support :infinity for Phoenix.Token max age
Closes #2755 

If would be awesome if this could be backported to the 1.3 branch if there's a release planned.

Patch:
diff --git a/lib/phoenix/token.ex b/lib/phoenix/token.ex
index b96153687..c8ec277b5 100644
--- a/lib/phoenix/token.ex
+++ b/lib/phoenix/token.ex
@@ -171,22 +171,11 @@ defmodule Phoenix.Token do
   def verify(context, salt, token, opts) when is_binary(salt) and is_binary(token) do
     secret = context |> get_key_base() |> get_secret(salt, opts)
 
-    max_age_ms =
-      if max_age_secs = opts[:max_age] do
-        trunc(max_age_secs * 1000)
-      else
-        # TODO: Default to 86400 on future releases.
-        Logger.warn ":max_age was not set on Phoenix.Token.verify/4. " <>
-                    "A max_age is recommended otherwise tokens are forever valid. " <>
-                    "Please set it to the amount of seconds the token is valid, such as 86400 (1 day)"
-        nil
-      end
-
     case MessageVerifier.verify(token, secret) do
       {:ok, message} ->
         %{data: data, signed: signed} = Plug.Crypto.safe_binary_to_term(message)
 
-        if max_age_ms && (signed + max_age_ms) < now_ms() do
+        if expired?(signed, opts[:max_age]) do
           {:error, :expired}
         else
           {:ok, data}
@@ -231,5 +220,17 @@ defmodule Phoenix.Token do
     KeyGenerator.generate(secret_key_base, salt, key_opts)
   end
 
+  defp expired?(_signed, :infinity), do: false
+
+  defp expired?(_signed, nil) do
+    # TODO: Default to 86400 on future releases.
+    Logger.warn ":max_age was not set on Phoenix.Token.verify/4. " <>
+                "A max_age is recommended otherwise tokens are forever valid. " <>
+                "Please set it to the amount of seconds the token is valid, such as 86400 (1 day)"
+    false
+  end
+
+  defp expired?(signed, max_age_secs), do: (signed + trunc(max_age_secs * 1000)) < now_ms()
+
   defp now_ms, do: System.system_time(:milliseconds)
 end


Test patch:
diff --git a/test/phoenix/token_test.exs b/test/phoenix/token_test.exs
index 4ecd412af..0296124f5 100644
--- a/test/phoenix/token_test.exs
+++ b/test/phoenix/token_test.exs
@@ -53,6 +53,11 @@ defmodule Phoenix.TokenTest do
     assert Token.verify(conn(), "id", token, max_age: 0.1) == {:error, :expired}
   end
 
+  test "supports :infinity for max age" do
+    token = Token.sign(conn(), "id", 1)
+    assert Token.verify(conn(), "id", token, max_age: :infinity) == {:ok, 1}
+  end
+
   test "supports signed_at in seconds" do
     seconds_in_day = 24*60*60
     day_ago_seconds = System.system_time(:seconds) - seconds_in_day