# Google Certificates

![Elixir CI](

A Lightweight GenServer that stores and caches Google's Public Certificates. 

The Google Certificates library makes it easy to verify and validate a [JWT]( issued by Google.
See the [how to use with the joken library](./readme.html#how-to-use-with-the-joken-library) section below for an example on how to accomplish this using this library combined with the [Joken]( library.

For more details, see Google's [backend-auth]( documentation, specifically the [verify the integrity of the id token]( section.

The default behavior is to use the `JWK` format ([/oauth2/v3/certs]( for certificates, but the `PEM` ([/oauth2/v1/certs]( format can be used if specified.

## Installation

This package can be installed
by adding `google_certs` to your list of dependencies in `mix.exs`:

def deps do
    {:google_certs, "~> 0.1"}

## Usage
Invoke `GoogleCerts.get/0` or `GoogleCerts.fetch/1` where needed.

### More Info
`GoogleCerts.CertificateCache` is an [Agent]( that will automatically be 
started and hydrated so that calls to `GoogleCerts.get/0` or `GoogleCerts.fetch/1` will return the cached results.

Every time `GoogleCerts.get/0` or `GoogleCerts.fetch/1` is invoked, the expiration of the cached certificates is checked. If 
the certificates are expired then a new network request is automatically issued to Google's API to refresh the cache. 

### Optional
If you wish to start `GoogleCerts.CertificateCache` manually you can set `GOOGLE_CERTS_ENABLE_AUTO_START=false`
or `auto_start?: false` and add it to your supervision tree.
  use Application
  alias GoogleCerts.CertificateCache
  def start(_type, _args) do
    children = [

    opts = [strategy: :one_for_one, name: Directory.Supervisor]
    Supervisor.start_link(children, opts)

There are three publicity available functions that are helpful.
1. `GoogleCerts.get/0`- Get cached certificates
1. `GoogleCerts.fetch/1` -  Get a certificate by it's kid (useful with `Joken.peek_header/1` to and `Joken.Signer.create/3` to create a signer)
1. `GoogleCerts.refresh/1` - Refresh a `GoogleCerts.Certificates` struct if the certificates are expired. Intended for internal use.

iex> GoogleCerts.get()                                              # get all certificates
iex> GoogleCerts.fetch("257f6a5828d1e4a3a6a03fcd1a2461db9593e624")  # get a certificate by its kid
iex> GoogleCerts.refresh(%GoogleCerts.Certificates{})               # refresh a set of certificates if they are expired

## How to use with the [Joken]( library

1. Create a custom verify hook
1. Register your custom verify hook with your JWTManager (custom module that `use Joken.Config` )
1. Use your JWTManager to verify and validate a JWT issued from Google.
   1. See [ueberauth]( and [ueberauth_google]( packages for retrieving a JWT from Google as part of your authentication. 

Create a custom verify hook
defmodule Crypto.VerifyHook do
  @moduledoc false

  use Joken.Hooks

  @impl true
  def before_verify(_options, {jwt, %Joken.Signer{} = _signer}) do
    with {:ok, %{"kid" => kid}} <- Joken.peek_header(jwt),
         {:ok, algorithm, key} <- GoogleCerts.fetch(kid) do
      {:cont, {jwt, Joken.Signer.create(algorithm, key)}}
      error -> {:halt, {:error, :no_signer}}

Register your custom verify hook with your JWTManager
defmodule Crypto.JWTManager do
  @moduledoc false

  use Joken.Config, default_signer: nil

  @iss ""
  # your google client id (usually ends in *
  defp aud, do: Application.get_env(:my_app, :google_client_id) 

  # reference your custom verify hook here

  @impl Joken.Config
  def token_config do
    default_claims(skip: [:aud, :iss])
    |> add_claim("iss", nil, &(&1 == @iss))
    |> add_claim("aud", nil, &(&1 == aud()))

Use your JWTManager to verify and validate a JWT issued from Google
iex> jwt = "eyJhbGciOiJSUzI1..."
iex> {:ok, claims} = JWTManager.verify_and_validate(jwt)

## Configuration (Optional)
See `GoogleCerts.Env` for all possible configurations. Most settings can be set using either 
system environment variables or elixir configurations.

# config/config.exs
config :google_certs, version: 1 # Use PEM format instead of JWK format. defaults to 3 for JWK

# bash
GOOGLE_CERTS_API_VERSION=1 iex -S mix phx.server # Use PEM format instead of JWK format. defaults to 3 for JWK