{"_id":"@boxyhq/remix-auth-saml","_rev":"7-886f146e7382e57f88cd9e6c5d2be0d8","name":"@boxyhq/remix-auth-saml","dist-tags":{"latest":"1.0.0"},"versions":{"1.0.0":{"name":"@boxyhq/remix-auth-saml","version":"1.0.0","keywords":["remix","remix-auth","auth","authentication","strategy","saml2","oauth2"],"author":{"url":"https://boxyhq.com","name":"BoxyHQ","email":"aswin@boxyhq.com"},"license":"MIT","_id":"@boxyhq/remix-auth-saml@1.0.0","maintainers":[{"name":"deepakp","email":"deepak@boxyhq.com"}],"dist":{"shasum":"a05b93587dd35da4f6c7334cc68cb9aef586d7ed","tarball":"https://registry.npmjs.org/@boxyhq/remix-auth-saml/-/remix-auth-saml-1.0.0.tgz","fileCount":5,"integrity":"sha512-4yBcNuE2rb8Fk0pAUzYd1JfBWHICSl7lGsWElS5PHNtNo2qvCtz0ZbyiGME0dWqod+D6Vjo5wjTZS3YgVyoWKw==","signatures":[{"sig":"MEUCIQC5O6eyzbPgVoUS5VDv2ueGLK5qZnObSHhp9MzCsVYW8QIgWLVBqFnizoQLjF9m0CXN+QvjnAGNaPzsFIx2QtfaxeI=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":9782,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJiLefdACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmp47A//SoVwBp8Pet/3am4Gms5AD2yUWZ6mGFKxL5ANV8C0xIoBL/ZY\r\nVkvjZeprGfDcuLMM1E4CtHix65f8i9jEl2/WekdeUaFwsXu3SSPin5Ruo17k\r\nVU817oaqVnpq19RfNfwW3QjQByb3UnsE5kTb1khDzb7c4kLtEx6DRwtzQHHP\r\nb4wA8aiZagRNJ/hKG5QihWM7IQTWebiIcPHswCsoq+LVnr7hfk8wGKqybRJx\r\nF8WPE65X7F2o+gDYp+hwdRt9CLXmD1UVQtaFwCBrVeaOOHp8Rw5o6H00GiNr\r\nFx4wBPEEgnrDSDDgfQ3YvqMejgPfb6Gf7yQAF5gjmsxorMer4iJgj4QO00vs\r\n+yF7cCgqDihy48Q/AsjAUGC52jm509CebQOLEPUu4Rf4An4czOwb2mrf8gLd\r\nyv2s2JZWQJUfHnduydeLVaU9oFRMPCNVaULQNe//ijTSfNE83/nqg8fDfS+l\r\ntKHieGfm7sKqgBi5M/2w8JmBWB8Xgqe2U7hd/C1mUVJX0s02ZXDacKQROUXm\r\nk6xN2vbEfA1SslKKn5QigeTDtzup0chWe7agvmr+7RQskH3ZwRAwtSn1rfmh\r\nOW5soczscH+dqrezqFxbLev1MFw2GZD2STE4JSvrKFM3Px21NIGqt2SawuHq\r\nMG6ta2yVIL28TiN5KYJ5tPaI2fTCaflJ/gM=\r\n=RoXK\r\n-----END PGP SIGNATURE-----\r\n"},"main":"./build/index.js","types":"./build/index.d.ts","gitHead":"b8c0e2644cd05dd4f0ad29caf55a69ee7c505af5","scripts":{"lint":"eslint --ext .ts,.tsx src/","test":"jest --config=config/jest.config.ts --passWithNoTests","build":"tsc --project tsconfig.json","coverage":"npm run test -- --coverage","typecheck":"tsc --project tsconfig.json --noEmit"},"_npmUser":{"name":"deepakp","email":"deepak@boxyhq.com"},"deprecated":"Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.","_npmVersion":"8.3.1","description":"A SAML strategy for Remix Auth, based on the OAuth2Strategy","directories":{},"_nodeVersion":"16.14.0","dependencies":{"remix-auth":"^3.0.0","remix-auth-oauth2":"^1.2.0"},"_hasShrinkwrap":false,"devDependencies":{"jest":"^26.6.3","react":"^17.0.2","eslint":"^7.26.0","ts-node":"^9.1.1","prettier":"^2.3.2","babel-jest":"^26.6.3","typescript":"^4.3.5","@babel/core":"^7.14.2","@types/jest":"^26.0.23","@remix-run/node":"^1.0.3","jest-fetch-mock":"^3.0.3","@remix-run/react":"^1.1.1","@babel/preset-env":"^7.14.1","eslint-plugin-jest":"^24.3.6","@babel/preset-react":"^7.13.13","eslint-plugin-unicorn":"^32.0.1","eslint-config-prettier":"^8.3.0","eslint-plugin-jest-dom":"^3.9.0","eslint-plugin-prettier":"^3.4.0","@babel/preset-typescript":"^7.13.0","@remix-run/server-runtime":"^1.0.0","@typescript-eslint/parser":"^4.23.0","@typescript-eslint/eslint-plugin":"^4.23.0"},"peerDependencies":{"@remix-run/server-runtime":"^1.0.0"},"_npmOperationalInternal":{"tmp":"tmp/remix-auth-saml_1.0.0_1647175645372_0.1711552302472097","host":"s3://npm-registry-packages"}}},"time":{"created":"2022-03-13T12:47:25.313Z","modified":"2026-03-20T16:43:29.770Z","1.0.0":"2022-03-13T12:47:25.729Z"},"author":{"url":"https://boxyhq.com","name":"BoxyHQ","email":"aswin@boxyhq.com"},"license":"MIT","keywords":["remix","remix-auth","auth","authentication","strategy","saml2","oauth2"],"description":"A SAML strategy for Remix Auth, based on the OAuth2Strategy","maintainers":[{"email":"deepak@boxyhq.com","name":"deepakp"},{"email":"aswin@boxyhq.com","name":"aswin_boxyhq"}],"readme":"# BoxyHQSAMLStrategy\n\nThe BoxyHQ SAML strategy is used to authenticate customers (typically enterprises having a SAML IdP) of your SaaS application. It extends the OAuth2Strategy.\n\n## Supported runtimes\n\n| Runtime    | Has Support |\n| ---------- | ----------- |\n| Node.js    | ✅          |\n| Cloudflare | ✅          |\n\n<!-- If it doesn't support one runtime, explain here why -->\n\n## BoxyHQ SAML Service\n\nBoxyHQ SAML is an open source service that handles the SAML login flow as an OAuth 2.0 flow, abstracting away all the complexities of the SAML protocol.\n\nYou can deploy BoxyHQ SAML as a separate service. [Check out the documentation for more details](https://boxyhq.com/docs/jackson/deploy)\n\n## Configuration\n\nSAML login requires a configuration for every tenant of yours. One common method is to use the domain for an email address to figure out which tenant they belong to. You can also use a unique tenant ID (string) from your backend for this, typically some kind of account or organization ID.\n\nCheck out the [documentation](https://boxyhq.com/docs/jackson/saml-flow#2-saml-config-api) for more details.\n\n## Usage\n### Install the strategy\n```bash\nnpm install @boxyhq/remix-auth-saml\n```\n\n### Create the strategy instance\n```ts\n// app/utils/auth.server.ts\nimport { Authenticator } from \"remix-auth\";\nimport {\n  BoxyHQSAMLStrategy,\n  type BoxyHQSAMLProfile,\n} from \"@boxyhq/remix-auth-saml\";\n\n// Create an instance of the authenticator, pass a generic with what your\n// strategies will return and will be stored in the session\nexport const authenticator = new Authenticator<BoxyHQSAMLProfile>(sessionStorage);\n\n\nauth.use(\n  new BoxyHQSAMLStrategy(\n    {\n      issuer: \"http://localhost:5225\", // point this to the hosted jackson service\n      clientID: \"dummy\", // The dummy here is necessary if the tenant and product are set dynamically from the client side\n      clientSecret: \"dummy\", // The dummy here is necessary if the tenant and product are set dynamically from the client side\n      callbackURL: new URL(\"/auth/saml/callback\", process.env.BASE_URL).toString(), // BASE_URL should point to the application URL\n    },\n    async ({ profile }) => {\n      return profile;\n    }\n  )\n);\n```\n\n### Setup your routes\n\n```tsx\n// app/routes/login.tsx\nexport default function Login() {\n  return (\n    <Form\n      method=\"post\"\n      action=\"/auth/saml\"\n    >\n      {/* We will be using user email to identify the tenant*/}\n      <label htmlFor=\"email\">Email</label>\n      <input\n        id=\"email\"\n        type=\"email\"\n        name=\"email\"\n        placeholder=\"johndoe@example.com\"\n        required\n      />\n      {/* Product can also be set dynamically, set to `demo` here */}\n      <input type=\"text\" name=\"product\" hidden defaultValue=\"demo\" />\n      <button type=\"submit\">\n        Sign In with SSO\n      </button>\n    </Form>\n  );\n}\n\n```\n\n```tsx\n// app/routes/auth/saml.tsx\nimport { ActionFunction, json } from \"remix\";\nimport { auth } from \"~/auth.server\";\nimport invariant from \"tiny-invariant\";\n\ntype PostError = {\n  email?: boolean;\n  product?: boolean;\n};\nexport const action: ActionFunction = async ({ request }) => {\n  const formData = await request.formData();\n\n  const email = formData.get(\"email\");\n  const product = await formData.get(\"product\");\n\n  const errors: PostError = {};\n  if (!email) errors.email = true;\n  if (!product) errors.product = true;\n\n  if (Object.keys(errors).length) {\n    return json(errors);\n  }\n\n  invariant(typeof email === \"string\");\n\n  const tenant = email.split(\"@\")[1];\n  return await auth.authenticate(\"boxyhq-saml\", request, {\n    successRedirect: \"/private\",\n    failureRedirect: \"/\",\n    context: {\n      clientID: `tenant=${tenant}&product=${product}`,\n      clientSecret: \"dummy\",\n    },\n  });\n};\n```\n\n```tsx\n// app/routes/auth/saml/callback.tsx\nimport type { LoaderFunction } from \"remix\";\nimport { auth } from \"~/auth.server\";\n\nexport const loader: LoaderFunction = async ({ request, params }) => {\n  return auth.authenticate(\"boxyhq-saml\", request, {\n    successRedirect: \"/private\",\n    failureRedirect: \"/\",\n  });\n};\n\n```","readmeFilename":"README.md"}