I’m glad to release the project I’ve been working for the last few months to learn Elixir: Asteroid (for Authorization Server on sTEROIDs) which is a standalone OAuth2 server.
OAuth2 is the main protocol used for decentralized access control on APIs. I guess most have already used it.
Before taking a year off, I was working in an IT consulting firm and specifically on the authentication, access control and identity management fields. At work we’ve designed secure architectures and deployed many authorization servers. I found that most lacked the extensibility needed to do what had to be done (read: bugs) and had poor performance when under heavy load. Hence the idea to create one in Elixir!
What is it made of?
An authorization server is at the junction of authentication schemes, user / application / device databases and token stores (state everywhere!), and is made of APIs and web UIs.
For API access, Asteroid can use
APIac.Authenticatorimplementation, such as:
APIac.Filterimplementation, such as:
For token backends you can use either Mnesia or Riak.
What is it capable of?
It implements the following standards:
- The OAuth 2.0 Authorization Framework (RFC6749)
- OAuth 2.0 Token Introspection (RFC7662)
- OAuth 2.0 Token Revocation (RFC7009)
- Proof Key for Code Exchange by OAuth Public Clients (RFC7636)
- OAuth 2.0 Dynamic Client Registration Protocol (RFC7591)
- OAuth 2.0 Authorization Server Metadata (RFC8414)
- JSON Web Token (JWT) Profile for OAuth 2.0 Access Tokens (draft-ietf-oauth-access-token-jwt-00)
- OAuth 2.0 Device Authorization Grant (draft-ietf-oauth-device-flow-15)
What is it not capable of?
You still have to implement authentication and authorization workflows by yourself, compared with other solutions that have it built-in.
Asteroid uses a lot of callback functions in its config files (for extensibility) such as:
config :asteroid, :oauth2_refresh_token_lifetime_callback, &Asteroid.Token.RefreshToken.lifetime/1
However, due to a bug in the Erlang standard library, those Elixir callback functions cannot be written in release configuration files. Distillery and
mix release fail at building releases, so you can only deploy it with mix (which is not recommended as far as I know).
I’d prefer keeping it as is and waiting for the next OTP version, but I’ll consider switching to MFA notation if needed. Lesson learnt here: release early!
Guidance regarding the use OAuth2
In my opinion:
- if you use a single domain, stick to using cookies as long as you can. The effort to understand and implement OAuth2 is just too high. Make sure to configure cookies in a secure manner.
- if you somehow have to use OAuth2:
- in simple scenarios (eg.: just one mobile app): keep OAuth2 server support in the same app and consider using https://github.com/danschultzer/ex_oauth2_provider
- otherwise (lots of third-parties, mobiles apps, etc.) it is worth deploying a standalone OAuth2 server such as CAS, Keycloak or IdentityServer (for the open-source ones)
Asteroid is not in the latter list because 1) it doesn’t have authentication workflows contrary to the servers listed 2) it doesn’t support OpenID Connect (OIDC) and you’ll probably want to use it sooner or later.
That said Asteroid might be interesting for some complex deployments: banking / PSD2 deployments (you’ll need to customize everything anyway), phone carriers implementing Mobile Connect (Erlang processes fit perfectly the need for backend connections to the phones), large fleet management (automotive?)…
I’ve deployed it to a Gigalixir server. If you want to test it the OAuth2 issuer is: https://repentant-brief-fishingcat.gigalixirapp.com/ (metadata at https://repentant-brief-fishingcat.gigalixirapp.com/.well-known/oauth-authorization-server)
Then follow this documentation.
- OpenID Connect support
- Authentication workflows: something similar to a form workflow (have been discussed here before) and that would be UI-independant (standard web, REST or LiveView) and some authentication modules (Social Login, MiniPOW, CAPTCHA, WebAuthn, and so on)
- More OAuth2 specifications support: token exchange, resource indicators, pushed request objects…
- Structured logging
Any feedback is welcome, and feel free to try to break the demo app
Have a good day!