This project is a generic server to connect to an OAuth identity service. Currently, the implemented services are GitHub and GitLab instances.
After having logged in with the service, this server forwards everything useful (secret token, refresh token if necessary) to the client-side. From there, the client-side code communicates directly with the service without intermediaries. This is possible with the implemented services (GitHub, GitLab) because they have CORS headers open on most API endpoints.
- Workflow example
- How to install toctoctoc
- How to use your toctoctoc server
- Endpoints
- Benefits of this approach
- Security
Let's say you have a client application. You want your users to be able to connect with GitHub and use their GitHub identity to communicate with Github (for instance, committing stuff on one of their repository).
The typical workflow would go like this:
- The users go on
your-client-application.com
. - They click on a "Login with GitHub" button. The link of this button would
look like this:
https://github.com/login/oauth/authorize?client_id=${client_id}&scope=${scope}&redirect_uri=${redirect_uri}
- On
github.com
, they share rights with your toctoctoc GitHub OAuth application. - They are redirected to their
destination
(see below for more instruction), usuallyyour-client-application.com
. Through this redirection, the toctoctoc server returns a GitHubaccess_token
to the client application. - From there, the client application can store the
access_token
(for instance, inlocalStorage
) and makes direct calls togithub.com
.
You can also set it up for GitLab if you need it.
- You need to install Node.js.
- A URL to access your toctoctoc server. It can be
http://localhost:[port]
on a development environment or a domain that points to your toctoctoc server.
Create an OAuth application for the service you want to handle with the server:
- A GitHub OAuth app:
for the
Authorization callback URL
, use the endpoint provided by your toctoctoc server:[your-toctoctoc-server-URL]/github-callback
. - And/or a GitLab OAuth app:
for the
Callback URL
, use the endpoint provided by your toctoctoc server:[your-toctoctoc-server-URL]/gitlab-callback
.
Clone the repository
git clone [email protected]:Scribouilli/toctoctoc.git
Install dependencies
npm install
You need to fill the client id and client secret of at least one service.
OAUTH_SERVICES_DECRYPTION_KEY
: a key to decryptoauth-services.json.encrypted
PORT
: The port this server will listen to. By default, it's4000
.HOST
: The host this server will listen to. By default, it'slocalhost
.TOCTOCTOC_ORIGIN
: The web content's origin of your toctoctoc server. It is defined by the protocol, the hostname and the port of the URL you use to access your toctoctoc server. (eg.http://localhost:4000
)
You can put these environment variables in an .env
file.
Oauth services are defined in the oauth-services.json file The one provided in the repo is an example file. It should not contain the real values because they should be kept secret
Instead, you should create a oauth-services.json.encrypted
file. It's an encrypted
oauth-services.json
file. It can be done easily using the helper web app.
It is available at <your toctoctoc origin>/oauth-services-config
npm run env-start:no-config
if you use a .env
file
npm run start:no-config
if you use environment variables directly
Changing the configuration requires the coordination of different changes in different places.
For instance, if you want to change the redirect_uri
of a gitlab config, you need to:
- set the new redirect uri in the oauth app on the gitlab instance
- change the encrypted configuration (in this repo of wherever your configuration is).
- You should change the encryption key as well
- deploy with the new encryption key and new encrypted configuration
You need to setup at least one service to use toctoctoc properly. Be sure that your OAuth application is setup correctly and your environment variables too.
Start the server. It will listen on the chosen port defined in your
.env
file.
npm start
On your client application, you have to authenticate your users through one of the services (GitHub or GitLab) and configure this authentication to use it with your toctoctoc server.
You request a user's GitHub identity through this endpoint:
https://github.com/login/oauth/authorize
To use it with toctoctoc, the mandatory parameters are:
client_id
: it's theclient_id
provided by your GitHub OAuth application for toctoctoc.scope
: the scope you want to ask for the needed rights, for examplepublic_repo,user:email
.redirect_uri
: it's the endpoint provided by your toctoctoc server for GitHub that ends like/github-callback
. Thisredirect_uri
must have adestination
parameter filled with ah URL: it enables toctoctoc to know where to redirect the user after fetching theaccess_token
.
Here is an example of link to let your users to authenticate through GitHub and
retrieve an access_token
with your toctoctoc server:
<a
href="https://github.com/login/oauth/authorize?client_id=XXXXXX&scope=public_repo,user:email&redirect_uri=http://my-toctoctoc-server-host.com/github-callback?destination=http://my-client-application.com"
>
Login with GitHub ๐
</a>
You can check GitHub's available scopes to only ask for the rights you need.
You request a GitLab authorization code through this endpoint:
https://gitlab.com/oauth/authorize
To use it with toctoctoc, the mandatory parameters are:
client_id
: it's theclient_id
provided by your GitHub OAuth application for toctoctoc.response_type
:code
.state
: a value that canโt be predicted, used by you to maintain state between the request to GitLab and the callback on your client application.scope
: the scope you want to ask for the needed rights, for exampleread_repository+write_repository+email
.redirect_uri
: it's the endpoint provided by your toctoctoc server for GitHub that ends like/gitlab-callback
. Thisredirect_uri
must have adestination
parameter filled with ah URL: it enables toctoctoc to know where to redirect the user after fetching theaccess_token
and therefresh_token
.
Here is an example of a link to let your users authenticate through GitLab and
retrieve an access_token
with your toctoctoc server:
<a
href="https://gitlab.com/oauth/authorize?client_id=XXXXXX&redirect_uri=http://my-toctoctoc-server-host.com/gitlab-callback?destination=http://my-client-application.com&response_type=code&state=XXXXXX&scope=read_repository+write_repository+email"
>
Login with GitLab ๐
</a>
Along with the access_token
, some other parameters are returned with the
destination
URL after the GitLab authentication:
refresh_token
: a token used to ask for a new GitLab OAuth token (check the section below for more information).expires_in
: the validity of theaccess_token
in milliseconds.state
: the value you provided to maintain state between the request to GitLab and the callback on your client application.
You can check GitLab's available scopes to only ask for the rights you need.
GitLab access tokens expire after two hours. On your client application, after
maximum two hours, you have to generate a new
access_token
using the refresh_token
attribute following the third step of
this documentation.
This server provides the following endpoints for you to use with your service OAuth application:
/github-callback
: route for GitHub to redirect to as redirect URL./gitlab-callback
: route for GitLab to redirect to as a redirect URL.
- This approach enables a client-side-only application to have an identity and private/personal storage associated to it without having to implement any of it. This reduces the cost and hassle of writing an application with private data
GitHub was a first choice to make it easy to prove the viability of the approach, but of course, it's a limited choice.
We plan on implementing the same for gitlab (both gitlab.com and self-hosted gitlab instances). And maybe one day ActivityPub-compatible identities...
-
A single server for different applications
-
no server-side code
The only thing this server has to protect are the credentials received from the services (for example GitHub's secret token).
Aside from adhering to POLA practices, this server has very little to do, so little to protect and it's good this way.
It does not keep trace of the token after having sent it to their destination.
One risk is a man-in-the-middle attack, but well-configured HTTPS takes care of this easily.
The only remaining risk probably comes from a complete take-over of the server via a remote-code execution (RCE) or complete system take-over. This could happen in the following ways:
- hardware-access attack (backdoor or direct malicious access to hardware)
- (I haven't studied it, but probably DNS-based attacks)
- exploitation of a known RCE vulnerability in the operating system (and probably network stack specifically)
- exploitation of a known RCE vulnerability in a dependency
- node.js itself
- in a dependency itself
- or via a supply-chain attack
Another important piece of the security puzzle are the various your-client-application.com
services themselves who need HTTPS and to make sure what's stored in the local storage is secure (so only highly-trusted third-party scripts, CSP, etc.)
An important note is that the different your-client-application.com
services are isolated from one another.
For the most part, the boring aspect of the project (accounting data from very small companies), HTTPS and up-to-date dependencies (OS, node.js and package.json dependencies) should probably keep things safe fairly easily.