{"id":29639360,"url":"https://github.com/storyblok/app-extension-auth","last_synced_at":"2025-07-21T20:37:56.168Z","repository":{"id":65562865,"uuid":"529280159","full_name":"storyblok/app-extension-auth","owner":"storyblok","description":"A JavaScript library for managing authentication for Storyblok plugins.","archived":false,"fork":false,"pushed_at":"2025-07-02T12:23:15.000Z","size":1737,"stargazers_count":3,"open_issues_count":5,"forks_count":3,"subscribers_count":18,"default_branch":"main","last_synced_at":"2025-07-02T12:29:42.503Z","etag":null,"topics":["authentication","core","plugins"],"latest_commit_sha":null,"homepage":"https://www.npmjs.com/package/@storyblok/app-extension-auth","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/storyblok.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":".github/CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2022-08-26T14:01:01.000Z","updated_at":"2025-07-02T12:19:10.000Z","dependencies_parsed_at":"2025-04-29T10:22:59.061Z","dependency_job_id":"edb5f183-fdd2-40bd-8cd3-5e155c7825dc","html_url":"https://github.com/storyblok/app-extension-auth","commit_stats":{"total_commits":42,"total_committers":1,"mean_commits":42.0,"dds":0.0,"last_synced_commit":"79de61b44f3f0794f457b75e0a6a5022be388e8a"},"previous_names":[],"tags_count":17,"template":false,"template_full_name":null,"purl":"pkg:github/storyblok/app-extension-auth","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/storyblok%2Fapp-extension-auth","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/storyblok%2Fapp-extension-auth/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/storyblok%2Fapp-extension-auth/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/storyblok%2Fapp-extension-auth/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/storyblok","download_url":"https://codeload.github.com/storyblok/app-extension-auth/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/storyblok%2Fapp-extension-auth/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":266375784,"owners_count":23919624,"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","status":"online","status_checked_at":"2025-07-21T11:47:31.412Z","response_time":64,"last_error":null,"robots_txt_status":null,"robots_txt_updated_at":null,"robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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","core","plugins"],"created_at":"2025-07-21T20:37:38.415Z","updated_at":"2025-07-21T20:37:56.157Z","avatar_url":"https://github.com/storyblok.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# @storyblok/app-extension-auth\n\nA JavaScript library for managing authentication for [Storyblok](https://www.storyblok.com) apps.\n\n## Migrating v1 to v2\n\nThe `@storyblok/app-extension-auth` v1 stored the access token in a cookie. However, in a future version of v2, the library will offer an adapter pattern, allowing you to store the access token elsewhere, such as in a dedicated database. The following breaking changes abstract the code to make this transition easier in the near future:\n\n### `sessionCookieStore` → `getSessionStore`\n\n```js\n// from\nimport { sessionCookieStore } from '@storyblok/app-extension-auth'\n\n// to\nimport { getSessionStore } from '@storyblok/app-extension-auth'\n```\n\n### `getSessionStore`\n\n```js\nconst sessionStore = getSessionStore(authHandlerParams)({\n  req: event.node.req,\n  res: event.node.res,\n})\n```\n\nThe `sessionStore` created by `sessionCookieStore` now exposes four methods: `get`, `getAll`, `put`, and `remove`.\n\n- The `getAll` method returns all app sessions, regardless of the spaces that the user has open.\n- The `put` and `remove` methods now return a `Promise\u003cboolean\u003e` instead of a `Promise\u003cvoid\u003e`.\n\n### `AuthHandlerParams`\n\n```js\nimport { authHandler } from '@storyblok/app-extension-auth'\nconst params: AuthHandlerParams = {\n  // ...\n}\nauthHandler(params)\n```\n\nThe parameter `AuthHandlerParams['cookieName']` has been renamed to `AuthHandlerParams['sessionKey']`.\n\n## Getting Started\n\nSee our starters:\n\n- [Next.js](https://github.com/storyblok/space-tool-plugins/tree/main/space-plugins/nextjs-starter)\n\n### Install the library\n\nInstall with:\n\n```shell\n# npm\nnpm install @storyblok/app-extension-auth\n\n#yarn\nyarn add @storyblok/app-extension-auth\n```\n\n### Set a URL\n\nDecide a URL for your app. As a first step, this should be a URL for local development. For this you will need a secure tunnel, for example [ngrok](https://ngrok.com/).\n\nTo open a secure tunnel with ngrok, run:\n\n```shell\nngrok http 3000\n```\n\n### Set up an App in Storyblok's Partner Portal\n\nCreate an App in Storyblok's Partner Portal. Then open app's settings, navigate to _Oauth 2_, and configure the following values:\n\n- **URL to your app**: the index page of your app. For example, `https://my-app.com/`.\n\n- **OAuth2 callback URL**: the api endpoint that will initiate the OAuth flow.\n  - Calculated as: `{baseUrl}/{endpointPrefix}/storyblok/callback`\n  - Example value: `https://my-app.com/api/connect/storyblok/callback`\n\nSubstitute `{baseUrl}` and `{endpointPrefix}` for your own values. These parameters will be referenced again in your code; see the next section.\n\n### Define constants\n\nIn your source code, create the following object (you will need it later):\n\n```typescript\nimport { AuthHandlerParams } from '@storyblok/app-extension-auth'\n\nexport const params: AuthHandlerParams = {\n  clientId: process.env.APP_CLIENT_ID,\n  clientSecret: process.env.APP_CLIENT_SECRET,\n  baseUrl: process.env.APP_URL,\n  successCallback: '/',\n  errorCallback: '/401',\n  endpointPrefix: '/api/connect',\n}\n```\n\nSome variables should be loaded via environmental variables (`.env.local`):\n\n- `clientId` -- The client ID is a public identifier for your apps. Find the Client ID in the app settings on Storyblok.\n- `clientSecret` -- The client secret is a secret known only to the application and the authorization server. Find the client secret in the app settings on Storyblok.\n  Load it into the application as an environmental variable.\n  It must be kept confidential.\n- `baseUrl` -- The base URL specifies the base URL to use for all relative authentication API endpoints created by authHandler().\n  The base URL must be absolute and secure with https.\n\n  For example, the base URL `https://my-app.my-domain.com/` will create the following api endpoints:\n\n  - `https://my-app.my-domain.com/storyblok` for initiating the authentication flow\n  - `https://my-app.my-domain.com/storyblok/callback` as the OAuth2 callback URL\n\nThe other variables can be hard-coded:\n\n- `successCallback` -- Specifies the URL that the user agent will be redirected to after a _successful_ authentication flow. Defaults to `\"/\"`.\n- `errorCallback` -- Specifies the URL that the user agent will be redirected to after an _unsuccessful_ authentication flow. If omitted, the user agent will receive a 401 response without redirect.\n- `endpointPrefix` -- Specifies the partial URL that is located between the baseUrl and the\n  authentication API endpoints.\n\n  For example, the following two properties\n\n  - `baseUrl: \"https://my-app.my-domain.com/\"`\n  - `endpointPrefix: \"api/authenticate\"`\n\n  will result in the API endpoints\n\n  - `https://my-app.my-domain.com/api/authenticate/storyblok` for initiating the authentication flow\n  - `https://my-app.my-domain.com/api/authenticate/storyblok/callback` as the OAuth2 callback URL\n\n### Create an API route\n\nIn NodeJS, create a dynamic route that handles the incoming requests with `authHandler()`. See [Framework examples](#routing-for-various-frameworks).\n\nFor example, in Next.js, create a file `pages/api/connect/[...slugs].ts`:\n\n```typescript\nimport { authHandler } from '@storyblok/app-extension-auth'\n\nexport default authHandler(params)\n```\n\n### Sign in\n\nSign in a user by redirecting to the api route: `/api/connect/storyblok`\n\nThis will initiate the oauth flow and redirect the user to the url specified in the `successCallback` URL. The following query parameters will be appended to the `successCallback` URL:\n\n- `userId`\n- `spaceId`\n\n### Retrieve the session\n\nNow, use these two query parameters to retrieve the session object:\n\n```typescript\nimport { sessionCookieStore } from '@storyblok/app-extension-auth'\n\nconst sessionStore = sessionCookieStore(params)(context)\nconst appSession = await sessionStore.get(query)\n\nif (appSession === undefined) {\n  // The user is not authenticated\n  //  redirect to /api/connect/storyblok\n}\n```\n\n### Use the session\n\nThe `AppSession` object contain user information for personalized content, and an access token to the Storyblok management API.\n\n```typescript\nconst { userId, spaceId, region, roles, accessToken } = appSession\n```\n\n### Routing\n\nStoryblok apps are embedded within Storyblok via iframes. When a page is requested, the server must get to know\n\n1. `spaceId`: the space the page is being embedded within\n2. `userId`: the user who loaded the page\n\nThese two values needs to be encoded within the page request.\n\nIf these two values cannot be retrieved, you need to initiate the OAuth flow by redirecting the user agent to `/api/connect/storyblok`. After a successful authentication, the `spaceId` and `userId` will be added as query parameters to the `successCallback` value. Now, it should be possible to retrieve the session like so\n\n```typescript\nimport { sessionCookieStore } from '@storyblok/app-extension-auth'\n\nconst sessionStore = sessionCookieStore(params)(context)\nconst appSession = await sessionStore.get(query)\n```\n\nWhen you redirect the user agent to a new page within your application, you need to _append the `spaceId` and `userId` query parameters_. Only if you do this can you retrieve the session from the `sessionCookieStore` from the other route.\n\n```typescript\nconst href = `/my/other/page?spaceId=${spaceId}\u0026userId=${userId}`\n```\n\n## How to run this application locally\n\nTo run OAuth locally, pass the `storyblokApiBaseUrl` property to the params object when calling the `authHandler` function in the target project (i.e. the plugin or application you want to test). With this parameter, you can change the target's backend environment.\n\n```typescript\nimport { AuthHandlerParams } from '@storyblok/app-extension-auth'\n\nimport { authHandler } from '@storyblok/app-extension-auth'\nconst params: AuthHandlerParams = {\n  // ...\n  storyblokApiBaseUrl: 'http://localhost:1234',\n}\nauthHandler(params)\n```\n\n## Routing for various frameworks\n\n### Next.js\n\nIn Next.js, create a file `pages/api/connect/[...slugs].ts`\n\n```typescript\nimport { authHandler } from '@storyblok/app-extension-auth'\n\nexport default authHandler(params)\n```\n\n### Express\n\nIn ExpressJs, create a route\n\n```typescript\nimport { authHandler } from '@storyblok/app-extension-auth'\n\napp.all('/api/connect/*', authHandler(params))\n```\n\n## Useful Resources\n\n- [Authentication Oauth2 flow](https://www.storyblok.com/docs/plugins/authentication-apps)\n- [Custom Applications](https://www.storyblok.com/docs/plugins/custom-application)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstoryblok%2Fapp-extension-auth","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fstoryblok%2Fapp-extension-auth","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstoryblok%2Fapp-extension-auth/lists"}