Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/boxyhq/jackson-remix-auth
Remix demo app showing Single sign-on (SSO) with Jackson
https://github.com/boxyhq/jackson-remix-auth
auth demo-app jackson remix remix-run saml saml2 single-sign-on sso
Last synced: 3 months ago
JSON representation
Remix demo app showing Single sign-on (SSO) with Jackson
- Host: GitHub
- URL: https://github.com/boxyhq/jackson-remix-auth
- Owner: boxyhq
- Created: 2022-03-04T17:05:22.000Z (almost 3 years ago)
- Default Branch: main
- Last Pushed: 2023-10-27T11:30:43.000Z (over 1 year ago)
- Last Synced: 2024-04-13T20:30:14.991Z (10 months ago)
- Topics: auth, demo-app, jackson, remix, remix-run, saml, saml2, single-sign-on, sso
- Language: TypeScript
- Homepage:
- Size: 1.15 MB
- Stars: 5
- Watchers: 5
- Forks: 1
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# Remix Demo App with Single Sign-On (SSO)
This demo shows how to use [BoxyHQSSOStrategy](https://www.npmjs.com/package/@boxyhq/remix-auth-sso) to integrate Single Sign-On (SSO) into any remix application.
Two different SSO Service Provider setups are shown in this demo
1. With a [hosted](#hosted-sso-service-provider) SSO Service Provider.
2. With the SSO Service Provider functionality [embedded](#embedded-sso-service-provider) within the remix app using resource routes.## Getting started
## Install dependencies
```
npm i
```## Set up the env
Create a `.env` file from `.env.example`
```
cp .env.example .env
```**NOTE**: You may have to tweak `.env` based on the type of SSO Provider setup i.e. Hosted vs Embedded. Refer the [SSO Provider Setup](#sso-provider-setup) section below.
## Start the app
```
npm run dev
```## SSO Provider Setup
We have two options when it comes to enabling SSO for a remix app. You can host the SSO feature (i.e. Jackson) as a standalone service or you could embed the SSO functionality inside the remix app with the help of our [npm](https://www.npmjs.com/package/@boxyhq/saml-jackson) package.
### Hosted SSO Service Provider
In this setup, you can use a hosted service endpoint for Jackson. See the [deploy](https://boxyhq.com/docs/jackson/deploy/service) guide on how to run Jackson as a service. Once you have the service set up, simply point the env `BOXYHQSSO_ISSUER` to the service URL.
For a quick test, setup `.env` with `BOXYHQSSO_ISSUER` as below:
```
BOXYHQSSO_ISSUER=https://sso.eu.boxyhq.com
CLIENT_SECRET_VERIFIER=dummy
```This uses a [our SaaS instance](https://sso.eu.boxyhq.com) of [jackson](https://github.com/boxyhq/jackson) as the SSO Service Provider. An SSO connection is preconfigured pointing to [Mock SAML IdP](https://mocksaml.com).
The tenant and product are locked into [`boxyhq.com`](app/routes/login.tsx#L60) and [`1eef7782-41d4-4a0a-b450-0857413b4f63`](app/routes/login.tsx#L78) for the Mock SAML IdP Connection.
### Embedded SSO Service Provider
This uses the [jackson npm package](https://www.npmjs.com/package/@boxyhq/saml-jackson) to embed the Single Sign-On feature without depending on an external service. See `JacksonProvider` in [auth.jackson.server.ts](app/auth.jackson.server.ts#L42) where the SSO controllers `{ connectionAPIController, oauthController }` are exposed. The resource routes for SSO flow are added in [app/routes/api](app/routes/api/).
For this setup, we will need some additional env for the following :
```typescript
db: {
engine: process.env.DB_ENGINE,
url: process.env.DB_URL,
type: process.env.DB_TYPE,
encryptionKey: process.env.DB_ENCRYPTION_KEY,
} as DatabaseOption,
clientSecretVerifier: process.env.CLIENT_SECRET_VERIFIER,
openid: {
jwsAlg: "RS256",
jwtSigningKeys: {
private: process.env.OPENID_RSA_PRIVATE_KEY!,
public: process.env.OPENID_RSA_PUBLIC_KEY!,
},
},
```Please refer to https://boxyhq.com/docs/jackson/deploy/env-variables for more info and set the variables in `.env`.
Once the app is running [configure](https://boxyhq.com/docs/jackson/sso-flow/#21-add-connection) an SSO Connection as shown below. Here we are going with a SAML SSO Connection.
Below adds a SAML SSO connection for https://mocksaml.com
curl --location --request POST 'http://localhost:3366/api/v1/connections' \
--header 'Authorization: Api-Key ' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'encodedRawMetadata=PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjxFbnRpdHlEZXNjcmlwdG9yIHhtbG5zOm1kPSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6bWV0YWRhdGEiIGVudGl0eUlEPSJodHRwczovL3NhbWwuZXhhbXBsZS5jb20vZW50aXR5aWQiIHZhbGlkVW50aWw9IjIwMjYtMDYtMjJUMTg6Mzk6NTMuMDAwWiI+CiAgPElEUFNTT0Rlc2NyaXB0b3IgV2FudEF1dGhuUmVxdWVzdHNTaWduZWQ9ImZhbHNlIiBwcm90b2NvbFN1cHBvcnRFbnVtZXJhdGlvbj0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6Mi4wOnByb3RvY29sIj4KICAgIDxLZXlEZXNjcmlwdG9yIHVzZT0ic2lnbmluZyI+CiAgICAgIDxLZXlJbmZvIHhtbG5zOmRzPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwLzA5L3htbGRzaWcjIj4KICAgICAgICA8WDUwOURhdGE+CiAgICAgICAgICA8WDUwOUNlcnRpZmljYXRlPk1JSUM0akNDQWNvQ0NRQzMzd255YlQ1UVpEQU5CZ2txaGtpRzl3MEJBUXNGQURBeU1Rc3dDUVlEVlFRR0V3SlYKU3pFUE1BMEdBMVVFQ2d3R1FtOTRlVWhSTVJJd0VBWURWUVFEREFsTmIyTnJJRk5CVFV3d0lCY05Nakl3TWpJNApNakUwTmpNNFdoZ1BNekF5TVRBM01ERXlNVFEyTXpoYU1ESXhDekFKQmdOVkJBWVRBbFZMTVE4d0RRWURWUVFLCkRBWkNiM2g1U0ZFeEVqQVFCZ05WQkFNTUNVMXZZMnNnVTBGTlREQ0NBU0l3RFFZSktvWklodmNOQVFFQkJRQUQKZ2dFUEFEQ0NBUW9DZ2dFQkFMR2ZZZXR0TXNjdDFUNnRWVXdUdWROSkg1UG5iOUdHbmtYaTlady9lNng0NUREMApSdVJPTmJGbEoyVDRSakFFL3VHK0FqWHhYUThvMlNaZmI5K0dnbUNIdVRKRk5nSG9aMW5GVlhDbWIvSGc4SHBkCjR2T0FHWG5kaXhhUmVPaXEzRUg1WHZwTWpNa0ozKzgrOVZZTXpNWk9qa2dRdEFxTzM2ZUFGRmZOS1g3ZFRqM1YKcHdMa3Z6Ni9LRkNxOE9Bd1krQVVpNGVabTVKNTdEMzFHempId2ZqSDlXVGVYME15bmRtbk5CMXFWNzVxUVIzYgoyL1c1c0dIUnYrOUFhcmdnSmtGK3B0VWtYb0x0VkE1MXdjZlltNmhJTHB0cGRlNUZRQzhSV1kxWXJzd0JXQUVaCk5meXJSNEplU3dlRWxOSGc0TlZPczRUd0dqT1B3V0dxelRmZ1RsRUNBd0VBQVRBTkJna3Foa2lHOXcwQkFRc0YKQUFPQ0FRRUFBWVJsWWZsU1hBV29acEZmd05pQ1FWRTVkOXpaMERQek5kV2hBeWJYY1R5TWYwejVtRGY2RldCVwo1R3lvaTl1M0VNRURuekxjSk5rd0pBQWMzOUFwYTRJMi90bWwrSnkyOWRrOGJUeVg2bTkzbmdtQ2dkTGg1WmE0CmtodVUzQU0zTDYzZzdWZXhDdU83a3dramgvK0xxZGNJWHNWR082WERmdTJRT3MxWHBlOXpJekxwd20vUk5ZZVgKVWpiU2o1Y2UvamVrcEF3N3F5VlZMNHhPeWg4QXRVVzFlazN3SXcxTUp2RWdFUHQwZDE2b3NoV0pwb1MxT1Q4TApyLzIyU3ZZRW8zRW1TR2RUVkdnazN4M3MrQTBxV0FxVGN5anI3UTRzL0dLWVJGZm9tR3d6MFRaNEl3MVpOOTlNCm0wZW8yVVNsU1JUVmw3UUhSVHVpdVNUaEhwTEtRUT09CjwvWDUwOUNlcnRpZmljYXRlPgogICAgICAgIDwvWDUwOURhdGE+CiAgICAgIDwvS2V5SW5mbz4KICAgIDwvS2V5RGVzY3JpcHRvcj4KICAgIDxOYW1lSURGb3JtYXQ+dXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6MS4xOm5hbWVpZC1mb3JtYXQ6ZW1haWxBZGRyZXNzPC9OYW1lSURGb3JtYXQ+CiAgICA8U2luZ2xlU2lnbk9uU2VydmljZSBCaW5kaW5nPSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6YmluZGluZ3M6SFRUUC1SZWRpcmVjdCIgTG9jYXRpb249Imh0dHBzOi8vbW9ja3NhbWwuY29tL2FwaS9zYW1sL3NzbyIvPgogICAgPFNpbmdsZVNpZ25PblNlcnZpY2UgQmluZGluZz0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6Mi4wOmJpbmRpbmdzOkhUVFAtUE9TVCIgTG9jYXRpb249Imh0dHBzOi8vbW9ja3NhbWwuY29tL2FwaS9zYW1sL3NzbyIvPgogIDwvSURQU1NPRGVzY3JpcHRvcj4KPC9FbnRpdHlEZXNjcmlwdG9yPg==' \
--data-urlencode 'defaultRedirectUrl=http://localhost:3366' \
--data-urlencode 'redirectUrl=["http://localhost:3366/*"]' \
--data-urlencode 'tenant=boxyhq.com' \
--data-urlencode 'product=saml-demo.boxyhq.com' \
--data-urlencode 'name=demo-config' \
--data-urlencode 'description=Demo SAML config'## Routes
1. `/` - Renders protected content if user is logged in.
2. `/login` - Renders a form (action - `/auth/sso`) with an input box which can take in an email that can be used to [switch](app/routes/auth.sso.tsx#L35) tenant dynamically.
3. `/logout`
4. `/auth/sso` (hosted),`/auth/sso/embed`(embedded) - Action handlers for login initiating the OAuth 2.0 flow to the IdP.
5. `/auth/sso/callback` (hosted),`/auth/sso/embed/callback` (embedded) - SSO Service Provider (Jackson) after parsing the SAML/OIDC response from IdP redirects back here with the authorization code. The SSO strategy uses the code to obtain the token and further the user profile and finally redirects back to `successRedirect` path.## Strategy Usage
`auth.server.ts`
```ts
// BASE_URL should be the hosting url of the app
// clientID and Secret set to 'dummy' here; they will be populated dynamically from the client side. The clientID is passed as a URL encoded string containing the tenant and product
export const auth = new Authenticator(sessionStorage);// This strategy points to a hosted jackson instance
auth.use(
new BoxyHQSSOStrategy(
{
issuer: process.env.BOXYHQSSO_ISSUER // "https://sso.eu.boxyhq.com",
clientID: "dummy",
clientSecret: "dummy",
callbackURL: new URL("/auth/saml/callback", BASE_URL).toString(),
},
async ({ profile }) => {
return profile;
}
)
);
// This strategy points to the same remix app host (resource routes are setup to handle SAML flow)
auth.use(
new BoxyHQSSOStrategy(
{
issuer: process.env.BOXYHQSSO_ISSUER, //same as the APP URL
clientID: "dummy",
clientSecret: process.env.CLIENT_SECRET_VERIFIER, // this env will be used to perform authentication at token endpoint
callbackURL: new URL("/auth/saml/embed/callback", BASE_URL).toString(),
},
async ({ profile }) => {
return profile;
}
),
"boxyhq-saml-embed"
);
```## FAQ
How is the tenant/product passed from the client side?
In the login form action handlers [app/routes/auth.sso.tsx](app/routes/auth.sso.tsx#L41), [app/routes/auth.sso.embed.tsx](app/routes/auth.sso.embed.tsx#L41), clientID is passed in the context param to authorize endpoint.
How can I test with a different "tenant/product"?
The demo uses email to detect the tenant. You can use an alternate mechanism such as directly asking for tenant information from the user. The same applies to "product". You might have to whitelist the product in [`validateProduct`](app/utils.server.ts#L20).