Current section

Files

Jump to
express lib express apns jwt_holder.ex
Raw

lib/express/apns/jwt_holder.ex

defmodule Express.APNS.JWTHolder do
use GenServer
import Joken
alias JOSE.JWK
alias Express.Configuration
@algorithm "ES256"
@ttl 50 * 60
defmodule State do
@type t :: %__MODULE__{jwt: String.t, iat: integer()}
defstruct ~w(jwt iat)a
end
def start_link, do: GenServer.start_link(__MODULE__, :ok, name: __MODULE__)
def init(:ok) do
now = Timex.now()
jwt = new(now)
{:ok, %State{jwt: jwt, iat: now}}
end
def get_jwt, do: GenServer.call(__MODULE__, :get_jwt)
def handle_call(:get_jwt, _from, state) do
state =
if expired?(state.iat) do
now = Timex.now()
jwt = new(now)
%State{jwt: jwt, iat: now}
else
state
end
{:reply, state.jwt, state}
end
defp new(iat) do
%{
"iss" => Configuration.APNS.team_id(),
"iat" => Timex.to_unix(iat)
}
|> token()
|> with_header_arg("alg", @algorithm)
|> with_header_arg("kid", Configuration.APNS.key_id())
|> with_signer(es256(apns_auth_key()))
|> sign()
|> get_compact()
end
def apns_auth_key do
if path = auth_key_path() do
JWK.from_pem_file(path)
else
if key = auth_key() do
key
|> String.replace("\\n", "\n")
|> JWK.from_pem()
end
end
end
def expired?(iat), do: Timex.diff(Timex.now(), iat, :seconds) > @ttl
defp auth_key_path, do: Configuration.APNS.auth_key_path()
defp auth_key, do: Configuration.APNS.auth_key()
end