Client library for consuming and working with OpenID Connect Providers
Available in Hex, the package can be installed as:
Add openid_connect
to your list of dependencies in mix.exs
:
def deps do
[{:openid_connect, "~> 1.0.0"}]
end
Most of the functions expect a config
map which means application developer should take care for the storage of those options, eg:
google_config = %{
discovery_document_uri: "https://accounts.google.com/.well-known/openid-configuration",
client_id: "CLIENT_ID",
client_secret: "CLIENT_SECRET",
redirect_uri: "https://example.com/session",
response_type: "code",
scope: "openid email profile"
}
authorization_uri(google_config)
Most major OAuth2 providers have added support for OpenIDConnect. See a short list of most major adopters of OpenIDConnect.
In your app code you will need to do a few things:
authorization_uri
for the provider(s)You can build the correct authorization URI for a provider with:
OpenIDConnect.authorization_uri(google_config)
In this case we are requesting that OpenIDConnect
build the authorization URI for
the google provider. You should use this URI for your users to link out to for
authenticating with the given provider
You will need an endpoint for the provider to redirect to after the user has authenticated. This is where the remainder of your steps will take place.
The JSON Web Token (JWT) must be fetched, using the key/value pairs from the response_type
params that were
part of the redirect to your application:
{:ok, tokens} = OpenIDConnect.fetch_tokens(google_config, %{code: params["code"]})
The JWT is encrypted and it should always be verified with the JSON Web Keys (JWK) for the provider:
{:ok, claims} = OpenIDConnect.verify(google_config, tokens["id_token"])
The claims
is a payload with the information from the scopes
you requested of the provider.
Now that you have the claims
payload you can use the user data to identify and set the user's session state for your app.
Setting your app's session state is outside the scope of this library.
# router.ex
get("/session", SessionController, :create)
get("/session/authorization-uri", SessionController, :authorization_uri)
# session_controller.ex
# you could also take the `provider` as a query param to pass into the function
def authorization_uri(conn, _params) do
google_config = Application.fetch_env!(:my_app, :google_oidc_config)
{:ok, uri} = OpenIDConnect.authorization_uri(google_config)
json(conn, %{uri: uri})
end
# The `Authentication` module here is an imaginary interface for setting session state
def create(conn, params) do
google_config = Application.fetch_env!(:my_app, :google_oidc_config)
with {:ok, tokens} <- OpenIDConnect.fetch_tokens(google_config, params["code"]),
{:ok, claims} <- OpenIDConnect.verify(google_config, tokens["id_token"]),
{:ok, user} <- Authentication.call(google_config, Repo, claims) do
conn
|> put_status(200)
|> render(UserView, "show.html", data: user)
else
_ -> send_resp(conn, 401, "")
end
end
We are very thankful for the many contributors
This library follows Semantic Versioning
At DockYard we are ready to help you build your next Elixir project. We have a unique expertise in Elixir and Phoenix development that is unmatched. Get in touch!
At DockYard we love Elixir! You can read our Elixir blog posts or come visit us at The Boston Elixir Meetup that we organize.
Please do! We are always looking to improve this library. Please see our Contribution Guidelines on how to properly submit issues and pull requests.
DockYard, Inc. © 2018