# NPM Library
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
SAML Jackson is available as an [npm package](https://www.npmjs.com/package/@boxyhq/saml-jackson) that can be integrated into any **Node.js** based web application framework.
Install the SDK using the command below.
```bash
npm install @boxyhq/saml-jackson
```
---
## Configuration Options
Please note that the initialization of `@boxyhq/saml-jackson` is async, you cannot run it at the top level.
```js
import jackson, {
type IConnectionAPIController,
type IOAuthController,
} from '@boxyhq/saml-jackson';
let oauth: IOAuthController;
let connection: IConnectionAPIController;
(async function init() {
const jackson = await require('@boxyhq/saml-jackson').controllers({
externalUrl: 'https://your-app.com',
samlAudience: 'https://saml.boxyhq.com',
oidcPath: '/api/oauth/oidc',
samlPath: '/api/oauth/saml',
db: {
engine: 'sql',
type: 'postgres',
url: 'postgres://postgres:postgres@localhost:5432/postgres',
},
});
oauth = jackson.oauthController;
connection = jackson.connectionAPIController;
})();
```
---
## Single Sign-On Connections
### Create SAML Connection
Create a new SAML Single Sign-On connection.
```js
await connection.createSAMLConnection({
tenant: 'boxyhq',
product: 'your-app',
rawMetadata: '', // Visit https://mocksaml.com to download Metadata
redirectUrl: ['https://your-app.com/*'],
defaultRedirectUrl: 'https://your-app.com/sso/callback',
});
```
```json
{
"defaultRedirectUrl": "https://your-app.com/sso/callback",
"redirectUrl": ["https://your-app.com/*"],
"tenant": "boxyhq",
"product": "your-app",
"clientID": "f7c909a5c72a5535847acf32558b2429a5172dd6",
"clientSecret": "cc6ba07bc42c2f449c9b0a3cc41c256dea08f705e1b44fdc",
"forceAuthn": false,
"idpMetadata": {
"sso": {
"postUrl": "https://mocksaml.com/api/saml/sso",
"redirectUrl": "https://mocksaml.com/api/saml/sso"
},
"slo": {},
"entityID": "https://saml.example.com/entityid",
"thumbprint": "d797f3829882233d3f01e49643f6a1195f242c94",
"validTo": "Jul 1 21:46:38 3021 GMT",
"loginType": "idp",
"provider": "saml.example.com"
},
"certs": {
"publicKey": "-----BEGIN CERTIFICATE----- ... -----END CERTIFICATE-----\r\n",
"privateKey": "-----BEGIN RSA PRIVATE KEY----- ... -----END RSA PRIVATE KEY-----\r\n"
}
}
```
### Update SAML Connection
Update a SAML Single Sign-On connection.
```js
await connection.updateSAMLConnection({
tenant: 'boxyhq',
product: 'your-app',
rawMetadata: '',
redirectUrl: ['https://your-app.com/*'],
defaultRedirectUrl: 'https://your-app.com/sso/callback-updated',
clientID: '',
clientSecret: '',
});
```
### Create OIDC Connection
Create a new OIDC Single Sign-On connection.
```js
await connection.createOIDCConnection({
tenant: 'boxyhq',
product: 'your-app',
redirectUrl: ['https://your-app.com/*'],
defaultRedirectUrl: 'https://your-app.com/sso/callback',
oidcDiscoveryUrl:
'https://accounts.google.com/.well-known/openid-configuration',
oidcClientId: '',
oidcClientSecret: '',
});
```
```json
{
"defaultRedirectUrl": "https://your-app.com/sso/callback",
"redirectUrl": ["https://your-app.com/*"],
"tenant": "boxyhq",
"product": "your-app",
"clientID": "749f95c4bd02b4adb6c0633249e70d5ad45b75e2",
"clientSecret": "2d730ac71c74e7d49dccf362c9a61005b6246cc65d6d0fa4",
"oidcProvider": {
"discoveryUrl": "https://accounts.google.com/.well-known/openid-configuration",
"clientId": "",
"clientSecret": "",
"provider": "accounts.google.com"
}
}
```
### Update OIDC Connection
Update an OIDC Single Sign-On connection.
```js
await connection.updateOIDCConnection({
tenant: 'boxyhq',
product: 'your-app',
redirectUrl: ['https://your-app.com/*'],
defaultRedirectUrl: 'https://your-app.com/sso/callback',
oidcDiscoveryUrl:
'https://accounts.google.com/.well-known/openid-configuration',
oidcClientId: '',
oidcClientSecret: '',
clientID: '',
clientSecret: '',
});
```
### Get SAML/OIDC Connections
Get the details of an existing SAML or OIDC Single Sign-On connection.
```js
// Using tenant and product
await connection.getConnections({
tenant: 'boxyhq',
product: 'your-app',
});
// Using the client ID
await connection.getConnections({
clientID: '.',
});
```
```json
[
{
"defaultRedirectUrl": "https://your-app.com/sso/callback",
"redirectUrl": ["https://your-app.com/*"],
"tenant": "boxyhq",
"product": "your-app",
"clientID": "...",
"clientSecret": "...",
"forceAuthn": false,
"idpMetadata": {
"sso": {
"postUrl": "https://mocksaml.com/api/saml/sso",
"redirectUrl": "https://mocksaml.com/api/saml/sso"
},
"slo": {},
"entityID": "https://saml.example.com/entityid",
"thumbprint": "d797f3829882233d3f01e49643f6a1195f242c94",
"validTo": "Jul 1 21:46:38 3021 GMT",
"loginType": "idp",
"provider": "saml.example.com"
},
"certs": {
"publicKey": "-----BEGIN CERTIFICATE----- ... -----END CERTIFICATE-----\r\n",
"privateKey": "-----BEGIN RSA PRIVATE KEY----- ... -----END RSA PRIVATE KEY-----\r\n"
}
}
]
```
### Delete SAML/OIDC Connection
Update a SAML or OIDC Single Sign-On connection.
```js
// Using tenant and product
await connection.deleteConnections({
tenant: 'boxyhq',
product: 'your-app',
});
// Using client ID and client secret
await connection.deleteConnections({
clientID: '',
clientSecret: '',
});
```
---
## Single Sign-On Authentication
### Handle OAuth 2.0 (or OIDC) Authorization request
To initiate the flow, the application must trigger an OAuth 2.0 (or OIDC) redirect to the authorization endpoint of your app. You'll use the `authorize` method within the authorization handler.
`authorize` will resolve the SSO URL (`redirect_url`) based on the connection configured for the tenant/product. The app needs to redirect the user to this URL. Keep in mind that the SSO URL structure is different based on the type of SSO Connection. For a SAML Connection, this will contain the `SAMLRequest` whereas for an OIDC Connection the SSO URL will be the Authorization endpoint with the OIDC request params (scope, response_type, etc.) attached.
```ts
await oauth.authorize({
tenant: 'boxyhq',
product: 'your-app',
redirect_uri:
'',
state:
'',
response_type: 'code',
code_challenge:
'',
code_challenge_method:
'',
scope:
'',
nonce:
'',
idp_hint:
'',
prompt: '',
});
```
```json
{
"redirect_url": "https://mocksaml.com/api/saml/sso?RelayState=boxyhq_jackson_...&SAMLRequest=nVbZkqs4En33V1T4...",
"authorize_form": ""
}
```
### Handle IdP Response
The response is sent back to your app after authentication at IdP. After the handling of this response, the profile of the authenticated user is extracted and stored against a short-lived code that is then sent back to the app. To handle the response use the appropriate method as detailed below:
#### SAML Response
Handle the response from the SAML Identity Provider. After successful authentication, IdP sends back (via browser POST) the `SAMLResponse` and `RelayState` to the Assertion Consumer Service (ACS) URL (`samlPath`) of the app. You'll use the `samlResponse` method within your ACS endpoint. This will parse and validate the SAML Response after which the user profile is extracted.
```js
await oauth.samlResponse({
SAMLResponse: '',
RelayState: '',
});
```
```json
{
"redirect_url": "https://your-app.com/sso/callback?code=5db7257fde94e062f6243572e31818d6e64c3097&state=c38ee339-6b82-43d3-838f-4036820acce9"
}
```
#### OIDC Response
Handle the response from the OIDC Identity Provider. After successful authentication, IdP sends back (via browser redirect) the `code` and `state` to the redirect URL (`oidcPath`) that handles the OIDC response. You'll use the `oidcAuthzResponse` method within your `oidcPath` handler. This will exchange the `code` for tokenSet (id_token and access_token) from the OIDC Provider. The "userinfo" endpoint of the OIDC Provider also gets invoked. Both the `id_token` claims and `userinfo` response are used to form the user profile.
```js
await oauth.oidcAuthzResponse({
code: '',
state: '',
});
```
```json
{
"redirect_url": "https://your-app.com/sso/callback?code=5db7257fde94e062f6243572e31818d6e64c3097&state=c38ee339-6b82-43d3-838f-4036820acce9"
}
```
### Request Access Token
Requests an `access_token` by passing the authorization `code` from the previous step along with other authentication details.
```js
const tenant = 'boxyhq';
const product = 'your-app';
await oauth.token({
code: '',
redirect_uri:
'',
client_id: `tenant=${tenant}&product=${product}`,
client_secret: 'dummy',
grant_type: 'authorization_code',
});
```
```json
{
"access_token": "6b81f03b60c34e46e740d96c7e6242923736a2d1",
"token_type": "bearer",
"expires_in": 300
}
```
### Fetch User Profile
Once the `access_token` has been fetched, you can use it to retrieve the user profile from the Identity Provider.
```js
const accessToken = '';
await oauth.userInfo(accessToken);
```
```json
{
"raw": {
"id": "1dda9fb491dc01bd24d2423ba2f22ae561f56ddf2376b29a11c80281d21201f9",
"email": "samuel@example.com",
"firstName": "Samuel",
"lastName": "Jackson",
"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier": "samuel@example.com"
},
"id": "1dda9fb491dc01bd24d2423ba2f22ae561f56ddf2376b29a11c80281d21201f9",
"email": "samuel@example.com",
"firstName": "Samuel",
"lastName": "Jackson",
"requested": {
"client_id": "f7c909a5c72a5535847acf32558b2429a5172dd6",
"state": "c38ee339-6b82-43d3-838f-4036820acce9",
"redirect_uri": "https://your-app.com/sso/callback",
"tenant": "boxyhq",
"product": "your-app",
"scope": []
}
}
```