Goat Guardian is a reverse-proxy authentication server. You can run it in front of an existing web application. It will handle all authentication, including OAuth and email-based login.
Goat Guardian is meant to make it easy to add support for authentication to your web application. It works great for demos, prototypes, internal web applications, and rapid development with a small team. It even works well for larger applications and teams that want an easy way to implement multiple forms of authentication!
Goat Guardian can be used in front of web applications written in any language/framework.
Goat Guardian is a reverse-proxy that runs in front of your web application. It proxies requests to your web application. It is similar to Apache or nginx.
Here is a simple network diagram of what it looks like to use Goat Guardian:
Goat Guardian received requests from the end-user. If it is a request to authenticate, Goat Guardian will directly handle it. If it is any other request, it will be forwarded to your web application.
In this document, end-user will be used to refer to to the user of the web application. In the diagram above, it is the blue guy all the way to the left.
Operator will be used to refer to the person who is setting up and using Goat Guardian. In most cases, this will be you, the person reading this document.
Upstream or upstream web app will be used to refer to the web application that runs behind Goat Guardian. In the diagram above, this refers to the web application all the way to right. In general, this should be an application that wants to authenticate users, but doesn't currently have any way to do authentication.
First, you must download and build Goat Guardian. You must have git
and
stack
installed to be able
to do this:
$ git clone https://github.com/arow-oss/goat-guardian.git
$ cd goat-guardian
$ stack install goat-guardian
This should build and install Goat Guardian as a binary in
~/.local/bin/goat-guardian
.
You can run it by running the binary, but there are some arguments you must specify either on the command line or as environment variables.
Here is an example of running goat-guardian
with all the required arguments:
$ goat-guardian \
--twitter-oauth-key Egex7CUsqQqSoEDjMivGtT1r0 \
--twitter-oauth-secret HCZPPaOmib64GP7QbQaEwrLwKswK8pQDe4UwsAS3EVJBupBj5l \
--session-key DORwMBc0sSvGvIDutozVyNnJwU7qTknHkqFWUhpoAElJruHWT0GH7qmTpKajqIxbkuyTN5M5mb9CuM5JECg7SKadylr1QMeZqo1yPexd07KEdMKCbqdxJBmgHoTbBLL8 \
--redir-after-login-url http://localhost:3000/after-login \
--sqlite-conn-string example-db.sqlite3
An explanation of all the options available is in a following section.
This command will run Goat Guardian on port 3000. If you open up a web browser and open http://localhost:3000/twitter/login you will be redirected to twitter to login.
Accessing any other URL will be reverse-proxied to your upstream web app. By default Goat Guardian assumes this is at http://localhost:8000/.
For example, if you access http://localhost:3000/some/other/path, Goat Guardian will reverse-proxy the request to http://localhost:8000/some/other/path. Your upstream web app will need to respond to this request.
If the end-user has logged in with Goat Guardian, Goat Guardian will add a
header X-UserId
. The value of the header should be an integer that
corresponds to the ID of the end-user. An example value will be something like
1
or 999
. Your upstream web app needs to check for this header upon
receiving a request in order to figure out whether the user has logged in or
not.
Other ways of interacting with Goat Guardian will be explained in a following section.
Goat Guardian provides multiple ways to perform authentication. Currently the following are suppored:
- Twitter OAuth
- Email-based login
An explanation of how to use each authentication method is provided in the following sections.
Twitter OAuth lets the end-user use Twitter to login to your application.
The login flow with twitter is as follows:
-
Direct the end-user to
/twitter/login
on Goat Guardian. (By default, this will be http://localhost:3000/twitter/login.)You will also need to specify a
next
URL query parameter with the URL to redirect the end-user to after they have finished authenticating on Twitter.next
could be something likehttp://localhost:3000/after-login
. -
Goat Guardian will redirect the end-user to twitter.com to login.
-
When the user logins in with Twitter, they will be redirected back to
/twitter/callback
on Goat Guardian. Goat Guardian will create a user ID in its database, and create a session cookie for the end-user. -
Goat Guardian will redirect the end-user to
next
query parameter specified above. -
Upon receiving the redirected request, Goat Guardian will add the
X-UserId
header and reverse-proxy the request to the upstream web app.
The command options and environment variables that affect Twitter OAuth are listed in a following section.
Email-based login is quite complicated compared to the other authentication methods.
Email-based login is actually broken down into multiple flows. The flows are as follows:
- Registering a new email address
- Login with an email address that has already been registered
- Changing the password if the end-user already know the current password.
- Resetting the password
Each of these flows is explained in detail in the following sections.
The flow for registering a new email address is described below:
-
The upstream web app must prepare a page with an HTML form asking the end-user for their email adress and a password to use for Goat Guardian.
It must set the
action
of the form toPOST
and the action to/email/register
for Goat Guardian. It must have three inputs, with the nameemail
,password
, andnext
.next
is the URL to redirect the end-user to after registering.next
could be something likehttp://localhost:3000/email-login-page
. -
When the end-user submits this form, Goat Guardian will intercept this request and send an email to the end-user asking them to confirm their email address.
-
When the end-user confirms their email address, they will be redirected to the
next
parameter from above. They are now able to login.
The flow for logging in with an email address that has already been registered and confirmed is described below:
-
The upstream web app must prepare a page with an HTML form asking the end-user for their email adress and a password:
It must set the
action
of the form toPOST
and the action to/email/login
for Goat Guardian. It must have three inputs, with the nameemail
,password
, andnext
.next
is the URL to redirect the end-user to after logging in.next
could be something likehttp://localhost:3000/after-login
. -
When the end-user submis this form, Goat Guardian will intercep this request and check the end-user's email and password. If it is correct, Goat Guardian will set a session cookie and redirect the end-user to the URL specified in the
next
parameter above. -
Upon receiving the redirected request, Goat Guardian will add the
X-UserId
header and reverse-proxy the request to the upstream web app.
The flow for changing the password for the end-user if the current password is known is described below:
-
The upstream web app must prepare a page with an HTML form asking the end-user for their current password and the new password to use.
It must set the
action
of the form toPOST
and the action to/email/change-password
for Goat Guardian. It must have three inputs, with the nameold-pass
,new-pass
, andnext
.next
is the URL to redirect the end-user to after registering. -
When the end-user submis this form, Goat Guardian will intercep this request and check the end-user's current password. If it is correct, Goat Guardian will change the password and redirect the end-user to the URL specified in the
next
parameter above. -
Upon receiving the redirected request, Goat Guardian will add the
X-UserId
header and reverse-proxy the request to the upstream web app.
Resetting a password involves sending the end-user an email to confirm who they are. The flow is as follows:
-
The upstream web app must prepare a page with an HTML form asking the end-user for their current password and the new password to use.
It must set the
action
of the form toPOST
and the action to/email/reset-password-send-email
for Goat Guardian. It must have two inputs, with the nameemail
andnext
.next
is the URL that Goat Guardian will forward the end-user to in order to set their new password. It is used in step 3. It could be something likehttp://localhost:3000/email-reset-pass-page
. -
When the end-user submits this form, Goat Guardian will intercept this request and send an email to the end-user asking them to confirm their email address.
-
When the end-user confirms their email address, they will be logged-in and redirected to the URL specified in the
next
argument in step 1. The HTTP HeaderX-UserId
will be set to their user ID. This page should be an HTML form asking the end-user for the new password to use.It must set the
action
of the form toPOST
and the action to/email/reset-password
for Goat Guardian. It must have two inputs, with the namenew-pass
andnext
.next
is the URL that Goat Guardian will forward the end-user to after changing their password. It is used in the next step. It could be something likehttp://localhost:3000
. -
When the end-user submits this form, Goat Guardian will change the password of the end-user and forward them to the URL in the
next
parameter.
There are a few other endpoints provided by Goat Guardian. They are described below.
Goat Guardian provides an endpoint that lets the end-user logout. The flow for using this is described below:
-
Have the end-user send a request to
/logout
with a query parameter callednext
.next
will be the URL to redirect the end-user to after logging them out. -
Goat Guardian will intercept this request and delete the session cookie for the end-user. Goat Guardian will then redirect the end-user to the URL from the
next
parameter. Since the end-user has been logged out, Goat Guardian will not set theX-UserId
HTTP header.
Goat Guardian will proxy all other URLs to the upstream web application.
Goat Guardian will add a header X-UserId
with a value of an integer. This
value can be used to identify and distinguish end-users.
Goat Guardian will add other headers depending on how the end-user logged in.
If the end-user logged in with Twitter, Goat Guardian will add the following headers:
X-Twitter-Token
: this is the end-user's Twitter token. It can be used to make requests to Twitter on the end-user's behalf.X-Twitter-Secret
: the end-user's Twitter secret. This is used with the Twitter token.X-Twitter-UserId
: the ID of the end-user on Twitter.X-Twitter-Screen-Name
: the screen name of the end-user on Twitter.
If the end-user logged in with email, Goat Guardian will add the following headers:
X-Email
: the email address of the end-user.
This section lists all the options that can be specified to Goat Guardian.
Command Line Flag | Environment Variable | Default | Description |
---|---|---|---|
--twitter-oauth-callback |
GG_TWITTER_OAUTH_CALLBACK_URL |
http://localhost:3000/twitter/callback |
The callback for the Twitter OAuth. The user will be redirected here after logging in on Twitter. This should be a URL controlled by Goat Guardian. |
--twitter-oauth-key |
GG_TWITTER_OAUTH_KEY |
(no default) | The OAuth key to use for Twitter. This should be a value like Egex7CUsqQqSoEDjMivGtT1r0 . You'll need to register with Twitter to get this value. |
--twitter-oauth-secret |
GG_TWITTER_OAUTH_SECRET |
(no default) | The OAuth secret to use for Twitter. This should be a value like HCZPPaOmib64GP7QbQaEwrLwKswK8pQDe4UwsAS3EVJBupBj5l . You'll need to register with Twitter to get this value. |
--db-conn-string |
GG_DB_CONN_STRING |
:memory: |
The connection string to use for the SQLite database used to store the end-user accounts. By default it just uses an in-memory database which is deleted when Goat Guardian stops running. You should probably specify this as something like /some/path/to/my-db.sqlite3 to save the end-user accounts to a file on disk. |
--session-key |
GG_SESSION_KEY |
(no default) | The encryption key used to encrypt/decrypt the session cookie sent to the end-user. This can be generated by running goat-guardian --generate-session-key . |
There are example web applications implementing all of the authentication flows described above.
(Currently there is only one example application, but we hope to add more. Please feel free to send a PR adding an example for your favorite language and framework.)
There are many features we would like to add to Goat Guardian at some point. The following are just a small taste. You can find many more features on the issue tracker.
-
Support other OAuth providers like Google, Github, and Facebook (#1)
-
Allow a user to login with either email or OAuth and link the accounts.
-
Provide a way for Goat Guardian to store user data in a database other than SQLite (#14)
-
Allow Goat Guardian settings to be specified in a configuration file (#17)
-
Specify "routing-rules" for Goat Guardian (#18). There are multiple uses for this:
- Serve static files as from a completely different server.
- Serve different routes from different microservices. For instance,
requests to
/users/*
could be routed to one microservice, while requests to/groups/*
could be routed to a different microservice. - Allow easy migration from a legacy system to a new system. For instance,
requests to
/v2/*
are directed to a new web application, while all other requests are handled by the legacy web application.
There are a few existing programs that have a similar feature set to Goat Guardian: login-with, oauth2_proxy, and kong. This section compares them to Goat Guardian.
login-with is similar to Goat Guardian. It acts as a "authentication microservice". It gives an easy way to implement authentication in a microservice architecture.
Here are some differences with Goat Guardian:
-
Goat Guardian is meant to be used as a reverse-proxy server. It should sit in front of your normal web application. It abstracts away the need to worry about authentication in your application. However, login-with is just another microservice in your microservice-architecture. Your web application will need to handle the JWT that login-with produces.
-
login-with doesn't handle email-based login. Goat Guardian does.
-
login-with can't be run under http (instead of https) for testing.
-
The documentation for login-with is lacking. Manual testing is required to figure out exactly how login-with operates. If you find the documentation for Goat Guardian lacking in any regard, please open an issue or send a PR.
oauth2_proxy is very similar to Goat Guardian. It acts as a reverse-proxy in the same way as Goat Guardian.
Here are some differences with Goat Guardian.
-
oauth2_proxy doesn't handle email-based registration and login. Goat Guardian does.
-
The documentation for oauth2_proxy is somewhat lacking. If you find the documentation for Goat Guardian lacking in any regard, please open an issue or send a PR.
-
oauth2_proxy only allows you to use one OAuth provider at a time. Goat Guardian allows you to use any that have been configured.
-
oauth2_proxy doesn't have any way to reverse-proxy endpoints if the end-user hasn't already loggedin. Goat Guardian lets the upstream application decide which pages to show based on whether or not the end-user has already logged in.
-
oauth2_proxy is mainly used to make internal web applications (for example, a self hosted version of Tiny Tiny RSS) available behind OAuth authorization. Goat Guardian is mainly intended to be used for public web applications meant to be used by the general public.
Kong is an API gateway. It acts as a reverse-proxy in the same way as Goat Guardian, but it handles much more than just authentication. It also handles monitoring, logging, rate-limiting, etc.
Here are some differences with Goat Guardian.
-
Kong is enterprise-ready and much more difficult to configure than Goat Guardian.
-
Kong doesn't really abstract away the need to handle authentication in your own web application.