{"id":19097370,"url":"https://github.com/boxyhq/remix-auth-sso","last_synced_at":"2025-07-12T22:40:36.511Z","repository":{"id":61271568,"uuid":"468327317","full_name":"boxyhq/remix-auth-sso","owner":"boxyhq","description":"An SSO strategy for Remix Auth,  based on the OAuth2Strategy","archived":false,"fork":false,"pushed_at":"2024-05-12T17:17:12.000Z","size":1015,"stargazers_count":18,"open_issues_count":0,"forks_count":0,"subscribers_count":5,"default_branch":"main","last_synced_at":"2025-04-19T04:41:23.075Z","etag":null,"topics":["authentication","oauth2","openid-connect","remix","saml2","sso-authentication","strategies"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/boxyhq.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2022-03-10T12:09:54.000Z","updated_at":"2025-01-06T08:45:43.000Z","dependencies_parsed_at":"2025-04-18T16:55:10.421Z","dependency_job_id":"5edbfd10-7d21-45b7-ae37-8825ab968756","html_url":"https://github.com/boxyhq/remix-auth-sso","commit_stats":null,"previous_names":[],"tags_count":3,"template":false,"template_full_name":"sergiodxa/remix-auth-strategy-template","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/boxyhq%2Fremix-auth-sso","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/boxyhq%2Fremix-auth-sso/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/boxyhq%2Fremix-auth-sso/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/boxyhq%2Fremix-auth-sso/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/boxyhq","download_url":"https://codeload.github.com/boxyhq/remix-auth-sso/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":251722709,"owners_count":21632999,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["authentication","oauth2","openid-connect","remix","saml2","sso-authentication","strategies"],"created_at":"2024-11-09T03:40:07.652Z","updated_at":"2025-04-30T14:40:17.673Z","avatar_url":"https://github.com/boxyhq.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# BoxyHQSSOStrategy\n\n**Attention ⚠️**: We have deprecated the earlier strategy `BoxyHQSAMLStrategy` (npm package: `@boxyhq/remix-auth-saml`). In case you are using that one please consider changing over to this strategy.\n\nThe BoxyHQSSOStrategy can be used to enable Single Sign-On (SSO) in your remix app. It extends the OAuth2Strategy.\n\n# Demo\n\nCheckout the demo at https://github.com/boxyhq/jackson-remix-auth\n\n## Supported runtimes\n\n| Runtime    | Has Support |\n| ---------- | ----------- |\n| Node.js    | ✅          |\n| Cloudflare | ✅          |\n\n\u003c!-- If it doesn't support one runtime, explain here why --\u003e\n\n## SAML Jackson Service\n\nSAML Jackson implements SSO as an OAuth 2.0 flow, abstracting away all the complexities of the underlying SAML/OIDC protocol.\n\nYou can deploy SAML Jackson as a separate service. [Check out the documentation for more details](https://boxyhq.com/docs/jackson/deploy)\n\n## Configuration\n\nSSO login requires a connection for every tenant/product 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/sso-flow/#21-add-connection) for more details.\n\n## Usage\n\n### Install the strategy\n\n```bash\nnpm install @boxyhq/remix-auth-sso\n```\n\n### Create the strategy instance\n\n```ts\n// app/utils/auth.server.ts\nimport { Authenticator } from \"remix-auth\";\nimport {\n  BoxyHQSSOStrategy,\n  type BoxyHQSSOProfile,\n} from \"@boxyhq/remix-auth-sso\";\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\u003cBoxyHQSSOProfile\u003e(\n  sessionStorage\n);\n\nauth.use(\n  new BoxyHQSSOStrategy(\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(\n        \"/auth/sso/callback\",\n        process.env.BASE_URL\n      ).toString(), // BASE_URL should point to the application URL\n    },\n    async ({ profile }) =\u003e {\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    \u003cForm method=\"post\" action=\"/auth/sso\"\u003e\n      {/* We will be using user email to identify the tenant*/}\n      \u003clabel htmlFor=\"email\"\u003eEmail\u003c/label\u003e\n      \u003cinput\n        id=\"email\"\n        type=\"email\"\n        name=\"email\"\n        placeholder=\"johndoe@example.com\"\n        required\n      /\u003e\n      {/* Product can also be set dynamically, set to `demo` here */}\n      \u003cinput type=\"text\" name=\"product\" hidden defaultValue=\"demo\" /\u003e\n      \u003cbutton type=\"submit\"\u003eSign In with SSO\u003c/button\u003e\n    \u003c/Form\u003e\n  );\n}\n```\n\n```tsx\n// app/routes/auth/sso.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 }) =\u003e {\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  // Get the tenant from the domain\n  const tenant = email.split(\"@\")[1];\n  return await auth.authenticate(\"boxyhq-sso\", request, {\n    successRedirect: \"/private\",\n    failureRedirect: \"/\",\n    context: {\n      clientID: `tenant=${tenant}\u0026product=${product}`,\n      clientSecret: \"dummy\",\n    },\n  });\n};\n```\n\n```tsx\n// app/routes/auth/sso/callback.tsx\nimport type { LoaderFunction } from \"remix\";\nimport { auth } from \"~/auth.server\";\n\nexport const loader: LoaderFunction = async ({ request, params }) =\u003e {\n  return auth.authenticate(\"boxyhq-sso\", request, {\n    successRedirect: \"/private\",\n    failureRedirect: \"/\",\n  });\n};\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fboxyhq%2Fremix-auth-sso","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fboxyhq%2Fremix-auth-sso","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fboxyhq%2Fremix-auth-sso/lists"}