Unlock the Power of OpenID Connect on the BEAM
In today's digital world, implementing secure and efficient authentication systems is more critical than ever. OpenID Connect has emerged as a powerful protocol, offering seamless and secure login experiences for applications. I recently delved deep into this topic during my talk at Code BEAM San Francisco, titled "Unlock the Power of OpenID Connect on the BEAM."
For those who couldn't attend, I'm excited to share the key insights and developments from that presentation through this series of blog posts. If you're interested in exploring further, you can watch the talk recording and download the slides.
Whether you're new to OpenID Connect or looking to enhance your application's security, these posts aim to provide valuable insights and practical guidance.
Part 2: Implementing OpenID Connect on the BEAM
Background and Motivation
Despite OpenID Connect's critical role in modern authentication, I found myself increasingly frustrated with the existing client implementations available for the BEAM ecosystem. Many libraries lacked comprehensive support for the full OpenID Connect specification, especially concerning advanced security features and compliance requirements. This gap not only complicated our development process but also raised concerns about the security and reliability of the applications we were building for our clients.
Determined to address these shortcomings, I took over the maintenance of the oidcc
library, originally developed by Indigo. The library already existed but did not fulfill the requirements I had set. I took over the project and implemented a completely new version to fully comply with the OpenID Connect Core specification and include optional security features crucial for high-stakes applications like banking and healthcare.
Implementing OpenID Connect on the BEAM
With the understanding of OpenID Connect's fundamentals and its security features, the next step is integrating it into applications built on the BEAM—the Erlang virtual machine that powers languages like Erlang and Elixir. Implementing OpenID Connect on the BEAM allows developers to leverage the concurrency and fault tolerance of the platform while providing secure authentication mechanisms in their applications.
Challenges with Existing Libraries:
- Incomplete Implementations: Existing libraries often lacked full support for the OpenID Connect specification, implementing only basic features necessary for simple authentication flows.
- Missing Security Features: Optional but crucial security features were frequently absent, which are essential for applications handling sensitive data.
- Lack of Compliance and Certification: Without full compliance and certification, there was a lack of trust and assurance in the reliability and security of these libraries.
Introducing oidcc
To address the need for a comprehensive and secure solution, I developed a completely new version of oidcc
, a fully compliant OpenID Connect client library designed specifically for Erlang and Elixir applications running on the BEAM.
What Is oidcc
?
oidcc
is an OpenID Connect client library that aims to provide:
- Complete Support for OpenID Connect Core Specification: Implements all mandatory features and many optional ones outlined in the OpenID Connect standard, ensuring broad compatibility with identity providers.
- Advanced Security Features: Includes support for optional security mechanisms such as PKCE, various client authentication methods, token validation, and more.
- Compliance and Certification: Designed to meet the compliance requirements set by the OpenID Foundation, providing confidence in its reliability and security.
- Ease of Use: Focuses on simplicity and developer-friendliness, making it straightforward to integrate into existing applications.
- Erlang and Elixir Support: Compatible with both Erlang and Elixir, offering flexibility for developers working in either language.
Key Features of oidcc
- Full OpenID Connect Core Implementation: Supports all standard authentication flows, including the Authorization Code Flow, Implicit Flow, Hybrid Flow, and more.
- Security by Default: Enforces best security practices out of the box, reducing the risk of misconfiguration.
- Dynamic Provider Configuration: Utilizes the OpenID Connect discovery mechanism to dynamically retrieve provider configurations.
- Token Management: Provides robust token handling, including validation, refreshing, and revocation support.
- Pluggable Architecture: Designed to be extensible, allowing developers to customize and extend functionality as needed.
- Comprehensive Documentation and Examples: Accompanied by detailed documentation and practical examples.
Companion Libraries
To facilitate seamless integration with popular web frameworks and tools in the BEAM ecosystem, oidcc
includes several companion libraries:
-
oidcc_cowboy
: Integration with Cowboy, a small, fast, and modern HTTP server for Erlang/OTP. -
oidcc_plug
: Support for Plug, allowing easy integration with Phoenix. -
phx_gen_oidcc
: A Phoenix generator that helps set up OpenID Connect authentication. -
ueberauth_oidcc
: Integration with Überauth, enabling developers to add OpenID Connect strategies to their authentication pipeline.
Why Choose oidcc
?
- Security and Compliance: Adheres strictly to the OpenID Connect specifications and incorporates advanced security features.
- Community and Support: Hosted under the Erlang Ecosystem Foundation's GitHub organization, benefiting from community contributions and oversight.
- Flexibility: Offers the flexibility to meet requirements for both simple and complex applications.
- Ease of Integration: Companion libraries and comprehensive documentation simplify integration.
Installation and Setup
Integrating oidcc
into your BEAM applications is straightforward, whether you're using Elixir or Erlang.
Installing oidcc
Add oidcc
and its companion libraries to your project's dependencies.
For Elixir Projects (mix.exs
):
defmodule MyApp.MixProject do
use Mix.Project
# ...
defp deps do
[
{:oidcc, "~> 3.1"}, # Core library
{:oidcc_plug, "~> 0.1.1"}, # Plug/Phoenix integration
{:ueberauth_oidcc, "~> 0.3.1"} # Überauth integration (optional)
]
end
end
Run mix deps.get
to fetch the dependencies.
For Erlang Projects (rebar.config
):
{deps, [
{oidcc, "~> 3.1"}, % Core library
{oidcc_cowboy, "~> 3.0"} % Cowboy integration
]}.
Run rebar3 get-deps
to fetch the dependencies.
Configuring Provider Introspection
Start a provider configuration worker to communicate with your OpenID Connect provider.
Elixir Example:
{:ok, _pid} =
Oidcc.ProviderConfiguration.Worker.start_link(%{
issuer: "https://example.com",
name: MyApp.OidcProvider
})
Erlang Example:
{ok, _Pid} =
oidcc_provider_configuration_worker:start_link(#{
issuer => <<"https://example.com">>,
name => {local, myapp_oidc_provider}
}),
Implementing Authentication
Elixir Example:
# Define the callback URI
callback_uri = "https://example.com/auth/callback"
# Create the redirect URI
{:ok, redirect_uri} =
Oidcc.create_redirect_url(
MyApp.OidcProvider,
client_id,
client_secret,
%{redirect_uri: callback_uri}
)
# Redirect the user to `redirect_uri`
# After authentication, exchange the authorization code for tokens
{:ok, token} =
Oidcc.retrieve_token(
auth_code,
MyApp.OidcProvider,
client_id,
client_secret,
%{redirect_uri: callback_uri}
)
Integrating with Web Frameworks
Using Cowboy (Erlang):
% Setup options
OidccCowboyOpts = #{
provider => myapp_oidc_provider,
client_id => <<"your_client_id">>,
client_secret => <<"your_client_secret">>,
redirect_uri => <<"http://example.com/auth/callback">>
},
% Success handler
OidccCowboyCallbackOpts =
maps:merge(OidccCowboyOpts, #{
handle_success => fun(Req, _Token, #{<<"sub">> := Subject}) ->
cowboy_req:reply(
200, #{}, [<<"Hello ">>, Subject, <<"!">>], Req
)
end
}),
% Register routes
Dispatch = cowboy_router:compile([
{'_', [
{"/auth/init", oidcc_cowboy_authorize, OidccCowboyOpts},
{"/auth/callback", oidcc_cowboy_callback, OidccCowboyCallbackOpts}
]}
]),
% Start the server
{ok, _} = cowboy:start_clear(http, [{port, 8080}], #{
env => #{dispatch => Dispatch}
}),
Using Plug/Phoenix (Elixir):
defmodule MyAppWeb.OidcController do
use MyAppWeb, :controller
alias Oidcc.Plug.{Authorize, AuthorizationCallback}
plug Authorize,
[
provider: MyApp.OidcProvider,
client_id: "your_client_id",
client_secret: "your_client_secret",
redirect_uri: &__MODULE__.callback_uri/0
]
when action in [:authorize]
plug AuthorizationCallback,
[
provider: MyApp.OidcProvider,
client_id: "your_client_id",
client_secret: "your_client_secret",
redirect_uri: &__MODULE__.callback_uri/0
]
when action in [:callback]
def callback_uri, do: url(~p"/oidc/callback")
def authorize(conn, _params), do: conn
def callback(
%Plug.Conn{
private: %{AuthorizationCallback => result}
} = conn,
_params
) do
case result do
{:ok, {_token, userinfo}} ->
conn
|> put_session("oidc_claims", userinfo)
|> redirect(to: "/")
{:error, reason} ->
conn
|> put_status(400)
|> render(:error, reason: reason)
end
end
end
Retrieving User Information and Introspection
Elixir Example:
# Retrieve user information
{:ok, claims} =
Oidcc.retrieve_userinfo(
token,
MyApp.OidcProvider,
client_id,
client_secret,
%{}
)
# Introspect the access token
{:ok, introspection} =
Oidcc.introspect_token(
token,
MyApp.OidcProvider,
client_id,
client_secret
)
Refreshing Tokens
Elixir Example:
# Refresh the access token
{:ok, refreshed_token} =
Oidcc.refresh_token(
token,
MyApp.OidcProvider,
client_id,
client_secret
)
API Token Validation
Ensuring the validity of API tokens is essential for securing your application's endpoints and protecting sensitive resources. The oidcc
library simplifies this task by offering robust support for API token validation through multiple methods.
Library Support for API Token Validation
The oidcc
library provides several ways to validate tokens received from clients:
-
JWT Verification: If your OpenID Connect provider issues access tokens as JWTs, you can perform local validation by verifying the token's signature using the provider's public keys and checking claims like issuer (
iss
), audience (aud
), and expiration time (exp
). - UserInfo Endpoint: Validate tokens by making a request to the UserInfo endpoint provided by the OpenID Connect issuer. A successful response confirms the token's validity and retrieves up-to-date user information.
- Token Introspection: Use the introspection endpoint to check a token's active status and retrieve associated metadata, useful for opaque tokens that cannot be validated locally.
Middleware Integration
To streamline token validation, oidcc
includes middleware components:
- Plug Middleware: In Elixir applications, integrate the provided Plug middleware into your pipeline to handle token extraction and validation for incoming requests.
- Cowboy Middleware: For Erlang applications using Cowboy, the library offers middleware that integrates token validation into your request handling.
By leveraging these validation methods and middleware components, you can enhance your application's security posture.
What's Next for oidcc
The development of oidcc
is an ongoing effort aimed at providing a comprehensive and secure OpenID Connect client library for the BEAM ecosystem. Looking ahead, several exciting developments and enhancements are planned to further improve the library and its utility in various applications.
Upcoming Features
Completion of FAPI 2.0 Certification: Work is underway to achieve full certification for the Financial-grade API (FAPI) 2.0 standards. This certification ensures that
oidcc
meets the stringent security and interoperability requirements necessary for applications in the financial sector and other high-security environments. Special thanks to Paul Swartz for his significant contributions to this effort.
Update: FAPI 2.0 is implemented, pending certification.Independent Security Review: An independent security audit is being conducted to thoroughly assess
oidcc
for potential vulnerabilities and to validate its security features. This review is made possible thanks to a collaboration with Erlang Solutions, who are providing their expertise to ensure the library's robustness.
Update: The review has been performed by SAFE and all findings have been remediated.Additional Companion Libraries: Plans are in place to develop companion libraries for other frameworks and tools within the BEAM ecosystem, such as integrating with the Ash Framework.
Support for Additional OpenID Protocols: Enhancements are being made to support more OpenID Connect protocols, such as Single Logout (SLO) and Self-Sovereign Identity (SSI). Implementing SLO will allow users to log out of multiple applications simultaneously, improving security and user experience.
Enhanced Documentation and Examples: Ongoing efforts to improve the documentation, provide more comprehensive examples, and create tutorials will make it easier for developers to adopt and implement
oidcc
in their projects.
How You Can Help
The continued success of oidcc
relies on the support and involvement of the community. Here are several ways you can contribute:
Vote for New Features
- GitHub Discussions: We've posted a list of potential extensions and new standards to implement on our GitHub Discussions page. If there's a feature you'd like to see, please give it an upvote. If it's not listed, feel free to create a new discussion thread. Your input helps us prioritize developments based on community interest.
Integrate oidcc
into Your Projects
-
Library Developers: If you're developing an authentication library that could benefit from
oidcc
, we'd be delighted to support its integration. We're happy to offer assistance to ensure a smooth implementation.
Try oidcc
and Provide Feedback
-
OpenID Connect Users: If you're using OpenID Connect in your applications, try out
oidcc
and let us know what you think. Your feedback is invaluable and helps us improve the library to better meet the community's needs.
Get Involved with the EEF
- Join an EEF Working Group: If you're involved in the BEAM ecosystem, consider joining a working group within the Erlang Ecosystem Foundation (EEF). Your participation can make a significant impact on the community's growth and direction.
Support the EEF as a Company
-
Corporate Sponsorship: If your company benefits from the BEAM ecosystem, consider sponsoring the EEF. Your support enables initiatives like
oidcc
and helps foster the development of the entire ecosystem, including community growth, educational resources, and collaborative projects that benefit everyone.
Top comments (0)