This project is a demo that shows how OAuth2 & OpenID Connect work.
we have 3 main folders, corresponding to the entities involved in the auth flow:
auth_server
is the authorization serverclient
is the application that needs the user's dataresource_server
is the service storing user's data
We need to create an .env
file in the auth_server
folder, containing the following properties:
PORT
: the port on localhostDB_CONNECTION_STRING
: connection string for the authenticating users dbNETWORK_PROTOCOL
: http/httpsHOST
: localhostRESOURCE_SERVER_ENDPOINT
: the resource server endpointSESSION_MAX_AGE
: is the expiration time (in milliseconds) of the session id associated to each user. Note: the tokens' lifetime should be lower or equal than this value, because tokens are assigned to the session object. Once the session is destroyed, tokens are lost as well.SESSION_STORAGE_CONNECTION_STRING
: the connection string of the db that stores the users' sessionsSESSION_SECRET
: the secret used to encrypt the session idPRIVATE_KEY
: the private key used to sign the JWTs. Must be RSA at least 2048 bitPUBLIC_KEY
: the public key corresponding to thePRIVATE_KEY
MAX_AUTH_CODE_LIFETIME
: the maximum number of seconds an auth code is considered validMAX_ACCESS_TOKEN_LIFETIME
: the maximum number of seconds an access token is considered valid, before being refreshedMAX_REFRESH_TOKEN_LIFETIME
: the maximum number of seconds a refresh token is considered validMAX_ID_TOKEN_LIFETIME
: maximum number of seconds an id token is considered valid
Then we need 2 storages:
- a Redis db for the users' sessions
- a MongoDb db for the users' necessary data for the authentication phase
See Docker Setup
We need to create an .env
file in the client
folder, containing the following properties:
PORT
: the port on localhostNETWORK_PROTOCOL
: http/httpsHOST
: localhostRESOURCE_SERVER_ENDPOINT
: the resource server endpointAUTH_SERVER_ENDPOINT
: the authorization server endpointSESSION_MAX_AGE
: is the expiration time (in milliseconds) of the session id associated to each user. Note: SeeSESSION_MAX_AGE
notes in the Authorization server.SESSION_STORAGE_CONNECTION_STRING
: the connection string of the db that stores the users' sessionsSESSION_SECRET
: the secret used to encrypt the session idAUTH_SERVER_PUBLIC_KEY
: the public key of the authorization server
Then we need a Redis storage for the session data, containing the state parameter and access token information (See Docker Setup).
We need to create an .env
file in the resource_server
folder, containing the following properties:
PORT
: the port on localhostNETWORK_PROTOCOL
: http/httpsHOST
: localhostDB_CONNECTION_STRING
: connection string for the users dbAUTH_SERVER_PUBLIC_KEY
: the public key of the authorization server
Then we need a MongoDB storage for the users' data (See Docker Setup).
For the external services requirements (like Redis and MongoDB), there is a docker-compose.yml
in the docker
folder. You can manually run them, or execute the start.sh
script, still in the docker
folder. Note: add a db_password.secret
both in the docker/auth_server
and docker/resource_server
folders. it contains the password that you have to type if you manually docker exec
the MongoDB containers.
The first step is to start the external services like Redis and MongoDB instances (with ./docker/start.sh
if you are using docker).
Then you can run the authorization server, the client, and the resource server with npm run auth_server
, npm run client
, and npm run resource_server
respectively. Note: always make sure that the authorization server is already listening when you start the client. The reason is that the client immediately registers to the authorization server.
In order to disable PKCE, for Postman testing for example, run the project in debug mode. To enable it, set the NODE_ENV
to debug for the authorization server and client:
NODE_ENV=debug npm run auth_server
NODE_ENV=debug npm run client
You can test the Code Flow by using the (currently Beta) feature of Postman called Postman Flow. This is the flow:
Note: I had to vertically stack the 2 parts of the flow, but they don't perfectly match: the line connecting "Start OAuth" and "Login" blocks is fragmented in 2 parts. If you find a way to share it as a Postman link (instead of using an image), please open a PR.