---
id: npm-library
title: Embedded quickstart
---

import Tabs from "@theme/Tabs"
import TabItem from "@theme/TabItem"

Ory Polis 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
```

:::info

ESM libraries and dynamic imports

Handling `jose` and `openid-client` in Bundled Server-Side Code:

The Ory Polis npm library dynamically imports the `jose` and `openid-client` packages because they have transitioned to ESM
(ECMAScript Modules).

If you are bundling your server-side code (e.g., in Next.js), these dependencies may be excluded during the build process. To
ensure they are included, follow these steps:

- Add dummy imports for jose and openid-client in your code.

- Configure `outputFileTracingIncludes` in your Next.js settings to explicitly include these dependencies.

Similar adjustments may be required for other frameworks that bundle server-side code.

:::

---

## 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.

<Tabs>
<TabItem value="01" label="Request" default>

```js
await connection.createSAMLConnection({
  tenant: "ory",
  product: "your-app",
  rawMetadata: "<raw-saml-metadata>", // Visit https://mocksaml.com to download Metadata
  redirectUrl: ["https://your-app.com/*"],
  defaultRedirectUrl: "https://your-app.com/sso/callback",
})
```

</TabItem>

<TabItem value="02" label="Response">

```json
{
  "defaultRedirectUrl": "https://your-app.com/sso/callback",
  "redirectUrl": ["https://your-app.com/*"],
  "tenant": "ory",
  "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"
  }
}
```

</TabItem>
</Tabs>

### Update SAML Connection

Update a SAML Single Sign-On connection.

```js
await connection.updateSAMLConnection({
  tenant: "ory",
  product: "your-app",
  rawMetadata: "<raw-saml-metadata>",
  redirectUrl: ["https://your-app.com/*"],
  defaultRedirectUrl: "https://your-app.com/sso/callback-updated",
  clientID: "<clientID of the SAML SSO Connection>",
  clientSecret: "<clientSecret of the SAML SSO Connection>",
})
```

### Create OIDC Connection

Create a new OIDC Single Sign-On connection.

<Tabs>
<TabItem value="01" label="Request" default>

```js
await connection.createOIDCConnection({
  tenant: "ory",
  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: "<OpenID Client ID>",
  oidcClientSecret: "<OpenID Client Secret>",
})
```

</TabItem>

<TabItem value="02" label="Response">

```json
{
  "defaultRedirectUrl": "https://your-app.com/sso/callback",
  "redirectUrl": ["https://your-app.com/*"],
  "tenant": "ory",
  "product": "your-app",
  "clientID": "749f95c4bd02b4adb6c0633249e70d5ad45b75e2",
  "clientSecret": "2d730ac71c74e7d49dccf362c9a61005b6246cc65d6d0fa4",
  "oidcProvider": {
    "discoveryUrl": "https://accounts.google.com/.well-known/openid-configuration",
    "clientId": "<OpenID Client ID>",
    "clientSecret": "<OpenID Client Secret>",
    "provider": "accounts.google.com"
  }
}
```

</TabItem>
</Tabs>

### Update OIDC Connection

Update an OIDC Single Sign-On connection.

```js
await connection.updateOIDCConnection({
  tenant: "ory",
  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: "<OpenID Client ID>",
  oidcClientSecret: "<OpenID Client Secret>",
  clientID: "<clientID of the OIDC SSO Connection>",
  clientSecret: "<clientSecret of the OIDC SSO Connection>",
})
```

### Get SAML/OIDC Connections

Get the details of an existing SAML or OIDC Single Sign-On connection.

<Tabs>
<TabItem value="01" label="Request" default>

```js
// Using tenant and product
await connection.getConnections({
  tenant: "ory",
  product: "your-app",
})

// Using the client ID
await connection.getConnections({
  clientID: "<clientID of the SSO Connection to be retrieved>.",
})
```

</TabItem>
<TabItem value="02" label="Response">

```json
[
  {
    "defaultRedirectUrl": "https://your-app.com/sso/callback",
    "redirectUrl": ["https://your-app.com/*"],
    "tenant": "ory",
    "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"
    }
  }
]
```

</TabItem>
</Tabs>

### Delete SAML/OIDC Connection

Update a SAML or OIDC Single Sign-On connection.

```js
// Using tenant and product
await connection.deleteConnections({
  tenant: "ory",
  product: "your-app",
})

// Using client ID and client secret
await connection.deleteConnections({
  clientID: "<clientID of the SSO Connection>",
  clientSecret: "<clientSecret of the SSO Connection>",
})
```

---

## 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.

<Tabs>
<TabItem value="01" label="Request" default>

```ts
await oauth.authorize({
  tenant: "ory",
  product: "your-app",
  redirect_uri: "<app redirect URI to which Ory Polis sents back the authorization code after authentication>",
  state: "<opaque value from the app which will be returned back from Ory Polis, this is need to prevent CSRF attacks>",
  response_type: "code",
  code_challenge: "<transformed value of code_verifier used to prevent interception of authorization_code in PKCE flow>",
  code_challenge_method: "<transformation method applied on code_verifier to generate code_challenge>",
  scope: "<can contain space separated values such as openid or even encoded tenant/product>",
  nonce: "<string value used to associate a client session with an ID Token in openid flow, and to mitigate replay attacks>",
  idp_hint:
    "<this will contain the clientID of the SSO connection that the user selects in the case of multiple ones configured for a tenant/product>",
  prompt: '<pass "login" to force authentication at the SAML IdP>',
})
```

</TabItem>

<TabItem value="02" label="Response">

```json
{
  "redirect_url": "https://mocksaml.com/api/saml/sso?RelayState=ory_jackson_...&SAMLRequest=nVbZkqs4En33V1T4...",
  "authorize_form": ""
}
```

</TabItem>
</Tabs>

### 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.

<Tabs>
<TabItem value="01" label="Request" default>

```js
await oauth.samlResponse({
  SAMLResponse: "<SAML Response from the SAML IdP>",
  RelayState: "<Relaystate from the original SAML request to the IdP>",
})
```

</TabItem>

<TabItem value="02" label="Response">

```json
{
  "redirect_url": "https://your-app.com/sso/callback?code=5db7257fde94e062f6243572e31818d6e64c3097&state=c38ee339-6b82-43d3-838f-4036820acce9"
}
```

</TabItem>
</Tabs>

#### 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.

<Tabs>
<TabItem value="01" label="Request" default>

```js
await oauth.oidcAuthzResponse({
  code: "<code received from OIDC IdP after authentication>",
  state: "<state from the original OIDC request to the IdP>",
})
```

</TabItem>

<TabItem value="02" label="Response">

```json
{
  "redirect_url": "https://your-app.com/sso/callback?code=5db7257fde94e062f6243572e31818d6e64c3097&state=c38ee339-6b82-43d3-838f-4036820acce9"
}
```

</TabItem>
</Tabs>

### Request access token

Requests an `access_token` by passing the authorization `code` from the previous step along with other authentication details.

<Tabs>
<TabItem value="01" label="Request" default>

```js
const tenant = "ory"
const product = "your-app"

await oauth.token({
  code: "<Authorization code received from Ory Polis at redirect_url after login at IdP>",
  redirect_uri: "<redirect_uri used in original authorization request to Ory Polis>",
  client_id: `tenant=${tenant}&product=${product}`,
  client_secret: "dummy",
  grant_type: "authorization_code",
})
```

</TabItem>

<TabItem value="02" label="Response">

```json
{
  "access_token": "6b81f03b60c34e46e740d96c7e6242923736a2d1",
  "token_type": "bearer",
  "expires_in": 300
}
```

</TabItem>
</Tabs>

### Fetch user profile

Once the `access_token` has been fetched, you can use it to retrieve the user profile from the Identity Provider.

<Tabs>
<TabItem value="01" label="Request" default>

```js
const accessToken = "<Access token from code exchange step above>"

await oauth.userInfo(accessToken)
```

</TabItem>

<TabItem value="02" label="Response">

```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": "ory",
    "product": "your-app",
    "scope": []
  }
}
```

</TabItem>
</Tabs>
