{"id":19806377,"url":"https://github.com/ory/integrations","last_synced_at":"2025-04-05T10:08:34.627Z","repository":{"id":39996364,"uuid":"408328869","full_name":"ory/integrations","owner":"ory","description":null,"archived":false,"fork":false,"pushed_at":"2024-10-17T15:59:50.000Z","size":416,"stargazers_count":19,"open_issues_count":16,"forks_count":24,"subscribers_count":8,"default_branch":"main","last_synced_at":"2024-10-29T16:05:15.383Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"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/ory.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"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}},"created_at":"2021-09-20T06:07:05.000Z","updated_at":"2024-08-29T21:37:18.000Z","dependencies_parsed_at":"2024-05-20T16:34:26.278Z","dependency_job_id":"bf1451ba-ebb0-40cd-a2f8-dea5e7a578bd","html_url":"https://github.com/ory/integrations","commit_stats":{"total_commits":64,"total_committers":11,"mean_commits":5.818181818181818,"dds":0.25,"last_synced_commit":"fc406da858b5ef85bef5156be5a77c0a0784b835"},"previous_names":[],"tags_count":38,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ory%2Fintegrations","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ory%2Fintegrations/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ory%2Fintegrations/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ory%2Fintegrations/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ory","download_url":"https://codeload.github.com/ory/integrations/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247318744,"owners_count":20919484,"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":[],"created_at":"2024-11-12T09:07:24.145Z","updated_at":"2025-04-05T10:08:34.602Z","avatar_url":"https://github.com/ory.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Integrations with Ory\n\nThis repository contains integrations for connecting with Ory Cloud.\n\n## Table of Contents\n\n\u003c!-- START doctoc generated TOC please keep comment here to allow auto update --\u003e\n\u003c!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE --\u003e\n\n- [NextJS](#nextjs)\n- [Vercel](#vercel)\n- [SDK Helpers](#sdk-helpers)\n  - [Type Guards](#type-guards)\n  - [UI Node Helpers](#ui-node-helpers)\n\n\u003c!-- END doctoc generated TOC please keep comment here to allow auto update --\u003e\n\n## NextJS\n\nTo connect a NextJS app with Ory, do the following in your NextJS App:\n\n```\n$ npm i --save @ory/integrations\n```\n\nThen create a file at `\u003cyour-nextjs-app\u003e/api/.ory/[...paths].ts` with the\nfollowing contents:\n\n```typescript\nimport { config, createApiHandler } from \"@ory/integrations/next-edge\"\n\nexport { config }\n\nexport default createApiHandler({\n  /* ... */\n})\n```\n\nYou need to set the environment variable `ORY_SDK_URL` to your\n[Ory Cloud Project SDK URL](https://www.ory.sh/docs/concepts/services-api). For\na list of available options head over to\n[`src/nextjs/index.ts`](src/next-edge/index.ts).\n\n## Vercel\n\nTo connect a non NextJS vercel app, do the following in your vercel app:\n\n```\n$ npm i --save @ory/integrations\n```\n\nThen create a file at `\u003cyour-vercel-app\u003e/api/oryproxy.js` with the following\ncontents:\n\n```javascript\nimport { config, createApiHandler } from \"@ory/integrations/next-edge\"\n\nexport { config }\n\nconst ah = createApiHandler({\n  /* ... */\n})\nconst apiHandlerWrapper = (req, res) =\u003e {\n  req.query.paths = req.url.replace(/^\\/api\\/.ory\\//, \"\").split(\"?\")[0]\n  ah(req, res)\n}\nexport default apiHandlerWrapper\n```\n\nThen add the following contents to `\u003cyour-vercel-app\u003e/vercel.json`:\n\n```\n{\n    \"rewrites\": [\n        { \"source\": \"/api/.ory/:match*\", \"destination\": \"/api/oryproxy\" }\n    ]\n}\n```\n\n## SDK Helpers\n\nThis package contains several helpers for using the Ory SDKs with TypeScript,\nJavaScript, and NodeJS.\n\n### Type Guards\n\nThis package includes type guards for identifying UI nodes.\n\n```ts\nimport {\n  isUiNodeImageAttributes,\n  isUiNodeInputAttributes,\n  isUiNodeScriptAttributes,\n  isUiNodeTextAttributes,\n  // ...\n} from \"@ory/integrations/ui\"\n\n// ...\n\nif (isUiNodeImageAttributes(node.attributes)) {\n  console.log(\"it is an image: \", node.attributes.src)\n}\n```\n\n### UI Node Helpers\n\nThis package contains convenience functions for UI nodes:\n\n- `import { getNodeLabel } from '@ory/integrations/ui'`: Returns the node's\n  label.\n- `import { getNodeId } from '@ory/integrations/ui'`: Returns a node's ID.\n- `import { filterNodesByGroups } from '@ory/integrations/ui'`: Filters nodes by\n  their groups.\n\nAn example of using the `filterNodesByGroups` function could be to map the\nUiNode[] to a certain JSX components.\n\nThe example below is from the [ory/themes](https://github.com/ory/themes)\nrepository and is used to map out the UI Nodes to JSX Components.\n\nUnderstanding `filterNodesByGroups` is quite easy if you think about it as a\nhierarchy:\n\n```ts\nconst nodes = [\n  {\n    group: \"webauthn\",\n    attributes: {\n      node_type: \"input\",\n      type: \"input\",\n    },\n  },\n  {\n    group: \"oidc\",\n    attributes: {\n      node_types: \"button\",\n      type: \"submit\",\n    },\n  },\n  {\n    group: \"oidc\", //\u003c-- take note here, we have 2 oidc groups\n    attributes: {\n      node_types: \"input\",\n      type: \"checkbox\"\n    }\n  }\n  {\n    group: \"foo\",\n    attributes: {\n      node_types: \"bar\",\n      type: \"bar\",\n    },\n  },\n]\n\nfilterNodesByGroups({\n  nodes: nodes,\n  groups: \"oidc,webauthn\", //\u003c-- filter these first\n  attributes: \"submit\", // \u003c-- then these will only take nodes containing the `submit` attributes\n  withoutDefaultAttributes: true, //\u003c-- dont add 'hidden' and 'script' fields when we specify attributes\n  excludeAttributes: \"checkbox\", // \u003c-- defining this wont do much here since we defined attributes. exclude the attributes to see what happens.\n})\n```\n\nHow will our output look like?\n\n```diff\n[\n-  {\n-    group: \"webauthn\",\n-    attributes: {\n-      node_type: \"input\",\n-      type: \"input\",\n-    },\n-  },\n+  {\n+    group: \"oidc\",\n+    attributes: {\n+      node_types: \"button\",\n+      type: \"submit\",\n+    },\n+  },\n-  {\n-    group: \"oidc\", //\u003c-- take note here, we have 2 oidc groups\n-    attributes: {\n-      node_types: \"input\",\n-      type: \"checkbox\"\n-    }\n-  }\n-  {\n-    group: \"foo\",\n-    attributes: {\n-      node_types: \"bar\",\n-      type: \"bar\",\n-    },\n-  },\n]\n```\n\nAn example is we have a UINode containing the group \"totp\" and attributes node\ntype \"input\".\n\n```json5\n{\n  group: \"totp\",\n  attributes: {\n    name: \"f\",\n    type: \"input\",\n    node_type: \"input\",\n  },\n}\n```\n\nOur end goal is to map it to HTML, something like this.\n\n```html\n\u003cinput type=\"input\" name=\"f\" /\u003e\n```\n\nTo achieve that, we could wrap it in a nifty JSX component which returns the\ncorrect component based on our UI node type.\n\nWe accept a `filter` object which is basically the `FilterNodesByGroups` type\nand return a `\u003cNode /\u003e` component, which is a component that helps us return our\nspecific HTML.\n\n```tsx\nexport const FilterFlowNodes = ({\n  filter,\n  includeCSRF,\n}: {\n  filter: FilterNodesByGroups\n  includeCSRF?: boolean\n}): JSX.Element | null =\u003e {\n  const getInputName = (node: UiNode): string =\u003e\n    isUiNodeInputAttributes(node.attributes) ? node.attributes.name : \"\"\n\n  // Here we are using our filterNodesByGroups to get the nodes we really want. We can even do some more filtering and mapping\n  const nodes = filterNodesByGroups(filter)\n    // we don't want to map the csrf token every time, only on the form level\n    .filter((node) =\u003e\n      getInputName(node) === \"csrf_token\" \u0026\u0026 !includeCSRF ? false : true,\n    )\n    .map((node, k) =\u003e\n      [\"hidden\"].includes(getNodeInputType(node.attributes))\n        ? {\n            node: \u003cNode node={node} key={k} /\u003e,\n            hidden: true,\n          }\n        : {\n            node: \u003cNode node={node} key={k} /\u003e,\n            hidden: false,\n          },\n    )\n\n  return nodes.length \u003e 0 ? (\n    \u003c\u003e\n      // we don't want hidden fields to create new gaps\n      {nodes.filter((node) =\u003e node.hidden).map((node) =\u003e node.node)}\n      \u003cdiv className={gridStyle({ gap: 16 })}\u003e\n        {nodes.filter((node) =\u003e !node.hidden).map((node) =\u003e node.node)}\n      \u003c/div\u003e\n    \u003c/\u003e\n  ) : null\n}\n```\n\nNow we can use our wrapper to return the HTML we want based on the `nodes`.\n\nHere we only want nodes that do not have the `hidden` attribute.\n\n```tsx\n\u003cFilterFlowNodes\n  filter={{\n    nodes: nodes,\n    excludeAttributes: \"hidden\",\n  }}\n/\u003e\n```\n\nAnother more complex example is to filter out the UI nodes to only retrieve the\n`oidc` and `password` groups. We also exclude the `default` group here with\n`withoutDefaultGroup: true`. Furthermore we do some exclusions on the\n`submit and `hidden`attributes, so any group which has an attribute containing a node type`submit`or`hidden`\nwill be filtered out.\n\n```tsx\n\u003cFilterFlowNodes\n  filter={{\n    nodes: nodes,\n    groups: [\"oidc\", \"password\"],\n    withoutDefaultGroup: true,\n    excludeAttributes: [\"submit\", \"hidden\"],\n  }}\n/\u003e\n```\n\nAnother example of us wanting the `oidc` and `webauthn` group (note: we can use\ncomma seperated strings instead of an array). We also exclude default attributes\nwith `withoutDefaultAttributes: true` which are `hidden` and `script` elements.\nThis will also only return us the nodes which have a `submit` attribute.\n\n```tsx\n\u003cFilterFlowNodes\n  filter={{\n    nodes: flow.ui.nodes,\n    groups: \"oidc,webauthn\",\n    withoutDefaultAttributes: true,\n    attributes: \"submit\",\n  }}\n/\u003e\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fory%2Fintegrations","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fory%2Fintegrations","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fory%2Fintegrations/lists"}