This is a very simple JWT-based SSO server that uses Google as an identity provider. It was written to ease the development process of new internal apps where I work and to allow employees to log into internal apps using their business Google accounts.
The login flow is quite simple:
- A user wants to log into an internal app
- The app redirects the user to
sso-proxy.url/sso/appname?state=randomness
- SSO Proxy verifies that the app exists and that the state is set, then:
- If the user is not already logged in, redirects the user to Google for authentication. The state passed to Google includes:
s
: a state value generated by SSO Proxyr
: the name of the appa
: the state value from the apph
: an MD5 hash of the above
- If the user is already logged in, asks the user to select which account they wish to use in order to log in. Selecting an account here will skip the Google login process. The user can also log in with a different account and be redirected to Google for authentication.
- If the user is not already logged in, redirects the user to Google for authentication. The state passed to Google includes:
- After the user authenticates with Google, they are redirected back to SSO Proxy where the state is verified and the validity of the access token is checked.
- The user is then redirected back to the app with a JWT (valid for 30 seconds) passed in the configured query parameter.
Node.js v16+ is required.
Install the dependencies:
npm i
Copy config.json.example
to config.json
and configure as needed. Save your Google OAuth key file at oauth.json
. You can get this file by creating an OAuth Client on the Google API Console.
You can validate your config file using a JSON Schema validator. If you're using ajv
, you can run the following command: ajv validate -s config.schema.json -d config.json --strict=false --errors=text
.
redirects
: This is where apps are configured. They are required to have the following properties:url
: The URL that SSO Proxy will redirect the user to.secret
: A secret used to sign the JWT token.query
: Configures what information is passed in the URL's query parameters. The following placeholder variables are available:{jwt}
: Will be replaced with the JWT.{state}
Will be replaced with the state generated by the app.{oauth.*}
: Will be replaced by data from Google. At the time of writing, the following details are available for use in this variable:
{ "id": "123456789012345678901", "email": "user@example.com", "verified_email": true, "name": "Example User", "given_name": "Example", "family_name": "User", "picture": "https://lh3.googleusercontent.com/a/ACNmcxbb2old2ilREbhdVM5S5N24ktjzWSEqM4HwUMpu=s96-c", "locale": "en", "hd": "example.com" }
jwt
: Configures the data that will be put in the JWT. Must havedefault
;overrides
is optional. Allquery
placeholder variables (with the exception ofjwt
) can be used here.default
: Specifies the default data for the JWT.overrides
: Allows for overriding JWT properties based on the value of other JWT properties. For example, the following override will setadmin
totrue
where theemail
isadmin@example.com
:
Alternatively, you can load a file containing the override rules by setting"overrides": { "email": { "admin@example.com": { "admin": true } } }
ssoproxy:require
to a relative path. Doing so allows you to control overrides that apply to multiple apps from a single file. Note that when using this method, you cannot set any other overrides."overrides": { "ssoproxy:require": "overrides.config.json" }
companyName
: The name of the company using SSO Proxy. This will be shown in the page titles, as well as the root page if a user is not logged in.domain
: The company domain. Only accounts with the email address ending in this domain will be allowed to log into SSO Proxy.port
: The port SSO Proxy should run on.secret
: A secret used in hashes and for signing cookies.callbackUrl
: By default, the first callback URL in theoauth.json
file will be used. This option can be used to set a different callback URL.