Branch: master
Find file Copy path
aa0392b Aug 16, 2018
3 contributors

Users who have contributed to this file

@safwank @bruce @axelson
176 lines (134 sloc) 4.08 KB

The Context and Authentication

Absinthe context exists to provide shared values to a given document execution. A common use would be to pass in the current user of a given request. The context is set at the call to, and cannot be modified over the course of a given execution.

Basic Usage

As a basic example let's think about a profile page, where we want the current user to be able to access basic information about themselves, but not other users.

First we'll need a very basic schema:

defmodule MyAppWeb.Schema do
  use Absinthe.Schema

  @fakedb %{
    "1" => %{name: "Bob", email: ""},
    "2" => %{name: "Fred", email: ""},

  query do
    field :profile, :user do
      resolve fn _, _, _ ->
        # How could we get a current user here?

  object :user do
    field :id, :id
    field :name, :string
    field :email, :string

A query we might want could look like:

  profile {

If we're signed in as user 1, we should get only user 1's email, for example:

  "profile": {
    "email": ""

In order to set the context, our call to should look like:, MyAppWeb.Schema, context: %{current_user: %{id: "1"}})

To access this, we need to update our query's resolve function:

query do
  field :profile, :user do
    resolve fn _, _, %{context: %{current_user: current_user}} ->
      {:ok, Map.get(@fakedb,}

And now it works!

Context and Plugs

When using Absinthe.Plug you don't have direct access to the call. Instead, we can use Absinthe.Plug.put_options/2 to set context values which Absinthe.Plug will use to pass it along to

Setting up your GraphQL context is as simple as writing a plug that inserts the appropriate values into the connection.

Let's use this mechanism to set our current_user from the previous example via an authentication header. We will use the same Schema as before.

First, our plug. We'll be checking the for the authorization header, and calling out to some unspecified authentication mechanism.

defmodule MyAppWeb.Context do
  @behaviour Plug

  import Plug.Conn
  import Ecto.Query, only: [where: 2]

  alias MyApp.{Repo, User}

  def init(opts), do: opts

  def call(conn, _) do
    context = build_context(conn)
    Absinthe.Plug.put_options(conn, context: context)

  @doc """
  Return the current user context based on the authorization header
  def build_context(conn) do
    with ["Bearer " <> token] <- get_req_header(conn, "authorization"),
    {:ok, current_user} <- authorize(token) do
      %{current_user: current_user}
      _ -> %{}

  defp authorize(token) do
    |> where(token: ^token)
    |> case do
      nil -> {:error, "invalid authorization token"}
      user -> {:ok, user}


This plug will use the authorization header to lookup the current user. If one is found, it correctly sets the absinthe context. If you're using Guardian or some other library that provides utilities for authenticating users you can use those here too, and just add their output to the context.

If there is no current user it's better to simply not have the :current_user key inside the map, instead of doing %{current_user: nil}. This way you an just pattern match for %{current_user: user} in your code and not need to worry about the nil case.

Using this plug is very simple. If we're just in a normal plug context we can just make sure it's plugged prior to Absinthe.Plug

plug MyAppWeb.Context

plug Absinthe.Plug,
  schema: MyAppWeb.Schema

If you're using a Phoenix router, add the context plug to a pipeline.

defmodule MyAppWeb.Router do
  use Phoenix.Router

  resource "/pages", MyAppWeb.PagesController

  pipeline :graphql do
    plug MyAppWeb.Context

  scope "/api" do
    pipe_through :graphql

    forward "/", Absinthe.Plug,
      schema: MyAppWeb.Schema