{"id":19987493,"url":"https://github.com/schibsted/account-sdk-browser","last_synced_at":"2025-08-01T00:39:32.428Z","repository":{"id":29335511,"uuid":"121385296","full_name":"schibsted/account-sdk-browser","owner":"schibsted","description":"Schibsted Account SDK for browsers","archived":false,"fork":false,"pushed_at":"2024-12-11T11:38:58.000Z","size":2445,"stargazers_count":16,"open_issues_count":28,"forks_count":12,"subscribers_count":16,"default_branch":"master","last_synced_at":"2025-01-13T16:15:57.775Z","etag":null,"topics":["authentication","browser","javascript","oauth2","oidc"],"latest_commit_sha":null,"homepage":"https://schibsted.github.io/account-sdk-browser/","language":"JavaScript","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/schibsted.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":".github/CONTRIBUTING.md","funding":null,"license":"LICENSE.md","code_of_conduct":"CODE_OF_CONDUCT.md","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":"2018-02-13T13:24:37.000Z","updated_at":"2024-12-11T11:39:01.000Z","dependencies_parsed_at":"2024-01-25T12:26:14.588Z","dependency_job_id":"974c7ca4-6000-4c33-b538-80c8c8aeb963","html_url":"https://github.com/schibsted/account-sdk-browser","commit_stats":{"total_commits":448,"total_committers":36,"mean_commits":"12.444444444444445","dds":0.7723214285714286,"last_synced_commit":"0213a4409f8ce5ed335cd3d4cdef522664eb005b"},"previous_names":[],"tags_count":93,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/schibsted%2Faccount-sdk-browser","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/schibsted%2Faccount-sdk-browser/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/schibsted%2Faccount-sdk-browser/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/schibsted%2Faccount-sdk-browser/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/schibsted","download_url":"https://codeload.github.com/schibsted/account-sdk-browser/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247430340,"owners_count":20937858,"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","browser","javascript","oauth2","oidc"],"created_at":"2024-11-13T04:36:38.420Z","updated_at":"2025-04-07T11:07:37.772Z","avatar_url":"https://github.com/schibsted.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![logo](https://www.schibsted.com/Global/LogoTypes/Logos%202014/SMG_Small_2014_RGB.png)](https://github.com/schibsted/account-sdk-browser)\n\n![Build Status](https://github.com/schibsted/account-sdk-browser/actions/workflows/pr.yml/badge.svg)\n[![Code coverage](https://codecov.io/gh/schibsted/account-sdk-browser/branch/master/graph/badge.svg)](https://codecov.io/gh/schibsted/account-sdk-browser)\n[![Snyk](https://snyk.io/test/github/schibsted/account-sdk-browser/badge.svg?targetFile=package.json)](https://snyk.io/test/github/schibsted/account-sdk-browser)\n\n# Schibsted account SDK for browsers\n\nWelcome! This is the home of the Schibsted account JavaScript SDK for use by any website that wishes\nto use Schibsted account to sign up and log in users. Use it to generate URLs for your site's \"Log\nin\" button, query the logged-in status of your users, and to check whether they have access to\nproducts and subscriptions, etc.\n\n## Getting started\n\nThis sdk mainly communicates with a service named Session Service, which is available on brand\ndomains (i.e. id.vg.no) to avoid Third-Party Cookie request.\n\nSince browsers started to block Third-Party Cookies, your top domain from local machine needs to\nmatch your Session Service top domain. Otherwise, the Session Service cookie will be a third-party cookie\nand will not be sent with a XHR request.\n\nThe same applies to cross scheme requests. The Session Service is hosted on https and therefore you need to [run your site with HTTPS locally](https://web.dev/how-to-use-local-https/).\n\nFor example if your `pre` domain is pre.sdk-example.com, and it uses id.pre.sdk-example.com Session Service\ndomain, your local domain should be local.sdk-example.com.\n\n1. Do `npm install --save @schibsted/account-sdk-browser`\n1. Use this library as you would any other npm module: `import { Identity, Monetization, Payment } from '@schibsted/account-sdk-browser'`\n   With CommonJS it is possible to `require` the modules Identity, Monetization and Payment\n   by appending `/identity`, `/monetization'` or `/payment'`.\n1. Build your site as you prefer. This library uses modern JavaScript syntax (including async/await\n   and other ES2017 and WHATWG features) by default. We recommend that you do any transpilation\n   yourself for the browser versions you need to cater to. See [this paragraph](#polyfills) for\n   info about our Babel-ified version and info about polyfills.\n1. Initiate the SDK and provide at least `clientId`, `env` and `sessionDomain`.\n\nIf this is for a new site and there is no sessionDomain yet, contact\n[support](mailto:schibstedaccount@schibsted.com) to initiate the process.\n\n## Migration to 5.x.x (ITP)\n\nFollow the [migration guide](./MIGRATION.md).\n\n## Simplified login widget\n\n1. Ensure that your site has no site specific terms and conditions in the Schibsted account login flow.\n1. Define rules for when and how often the simplified login prompt should be shown to unique users on your site. How you do this is up to you, but we recommend starting with showing the prompt once per user before potentially increasing this frequency over time.\n1. Set up a function to check if users landing on your domain [is logged in](https://schibsted.github.io/account-sdk-browser/Identity.html#isLoggedIn) to your site.\n1. If the user is not logged-in to your site, call the [showSimplifiedLoginWidget](https://schibsted.github.io/account-sdk-browser/Identity.html#showSimplifiedLoginWidget) function. The `showSimplifiedLoginWidget` accepts the same params as login function (`state` is required, it might be string or async function). If the simplified login prompt is to be loaded, `showSimplifiedLoginWidget` will return `true`.\n1. Set up a way to store information about which users have been shown the simplified login prompt. How you do this is up to you, but one way is to use localStorage. Use this information to execute on the rules defined in #2.\n\n## Example project\n\nThere is an example that demonstrates how the SDK can be used. The code is\n[here](https://github.com/schibsted/sdk-example), and you can see it live\n[here](https://pro.sdk-example.com). You have a use-case that we haven't thought of? Ask us to add\nit by creating an [issue](https://github.com/schibsted/sdk-example/issues/new).\n\nYou can use that code as inspiration or just fork and play with it. The account-sdk-browser NPM\nmodule is used for authenticating the user with Schibsted account. Take a look at how the SDK is\ninitialized.\n\nWhen a user wants to log in to your site, you direct them to a UI flow hosted by **Schibsted Account**. \nWe authenticate the user and redirect them back to your site. This final redirect back to your site is performed in accordance with the OAuth2 specification. \nThis means we pass a `code` in the query string of that redirect URI.\nYou can use that `code` on your site's backend, along with your client credentials (client ID and secret), to obtain an *Access Token* (AT) and a *Refresh Token* (RT). \nYou should not send the AT (and **never** the RT!) to the browser. Instead, keep them on the server side and associate them with the specific user session. \nThis allows you to call Schibsted Account APIs on behalf of that user.\n\n\n## Events\n\nThe SDK fires events when something we deem interesting is happening. For example the\n[Identity](https://schibsted.github.io/account-sdk-browser/Identity.html) class\nemits some events when the user is logged in or logged out. This SDK uses a familar interface that's\nvery similar to Node's [EventEmitter](https://nodejs.org/api/events.html). The most important\nmethods are `.on(eventName, listener)` (to subscribe to an event) and `.off(eventName, listener)`\n(to unsubscribe to an event).\n\n## Identity\n\nLet's start with a bit of example code:\n\n#### Example\n\n```javascript\nimport { Identity } from '@schibsted/account-sdk-browser'\n\nconst identity = new Identity({\n    clientId: '56e9a5d1eee0000000000000',\n    redirectUri: 'https://awesomenews.site', // ensure it's listed in selfservice\n    env: 'PRE', // Schibsted account env. A url or a special key: 'PRE', 'PRO', 'PRO_NO', 'PRO_FI' or 'PRO_DK'\n    sessionDomain: 'https://id.awesomenews.site', // client-configured session-service domain\n})\n\nasync function whenSiteLoaded() {\n    const loginContainer = document.getElementById('login-container')\n    if (await identity.isLoggedIn()) {\n        const user = await identity.getUser()\n        const span = document.createElement('span')\n        span.textContent = `Hello ${user.givenName}`\n        loginContainer.appendChild(span)\n    } else {\n        loginContainer.innerHTML = '\u003cbutton class=\"login-button\"\u003eLog in\u003c/button\u003e'\n    }\n}\n\nfunction userClicksLogIn() {\n    identity.login({ state: 'some-random-string-1234-foobar-wonky-pig' })\n}\n```\n\n#### Regarding `state`\n\nThis parameter is an OpenID Connect parameter (described in [this paragraph in the\nspec](http://openid.net/specs/openid-connect-core-1_0.html#rfc.section.3.1.2.1)). It's formatted as\nan opaque string. This means you can send anything that can be serialized to a string. In practice,\nwe have good experience sending something like a JSON value like a base64-url-encoded value — it's\njust an easy way to avoid browsers or backends messing with special characters.\n\nBut as a trivial example, if you call `Identity.login(..)` with params\n`redirectUri=https://site.com\u0026state=article%3D1234` — then at the end of the authentication flow,\nthe user will be sent back to your redirectUri, and the `state` parameter will be forwarded along\nwith the auth `code` parameter.\n\nIt is recommended that you provide a unique identifier as part of the state, to prevent CSRF\nattacks. For example this can be accomplished by:\n1. Your backend generates random token: `1234abcd`, saves it in some tokenCache, and forwards to\n   your browser frontend\n1. Your frontend calls `Identity.login` with `state = base64Urlencode({ token: '1234abcd', article:\n   '1234', ... })`\n1. When auth flow completes, the user is redirected back to your site. Then, your backend sees the\n   query parameters `code` (which it can exchange for OAuth tokens for the user) and `state`\n1. Your backend can do `decodedState = base64Urldecode(query.state)` and then verify that its\n   `tokenCache.contains(decodedState.token)`. If that fails, then possibly a CSRF attack was\n   attempted. If successful, remove the token from the tokenCache so the same token can't be used\n   again, and continue to show `decodedState.article`\n\n#### Authentication methods\n\nAlthough Schibsted account abstracts away the details of how the users sign up or log in, it's worth\nmentioning that your end users have a few ways to log in:\n\n* Username \u0026 password: pretty self-explanatory; users register using an email address and a\n  self-chosen password\n* Passwordless - email: here, the users enter their email address and receive a one-time code that\n  they can use to log in\n* Multifactor authentication: first client indicates which methods should be preferred, later these\n  will be included (if fulfilled) in `AMR` claim of IDToken\n\nThe default is username \u0026 password. If you wish to use one of the passwordless login methods, the\n`login()` function takes an optional parameter called `acrValues` (Authentication Context Class Reference).\nThe `acrValues` parameter with multifactor authentication can take following values:\n - `eid` - authentication using BankID (for DEV and PRE environments you can choose between country specific solution by specifying `eid-no` or `eid-se` instead)\n - `otp-email` - passwordless authentication using code sent to registered email\n - `password` - force password authentication (even if user is already logged in)\n - `otp` - authentication using registered one time code generator (https://tools.ietf.org/html/rfc6238)\n - `sms` - authentication using SMS code sent to phone number\n - `password otp sms` - those authentication methods might be combined\n\nThe classic way to authenticate a user, is to send them from your site to the Schibsted account\ndomain, let the user authenticate there, and then have us redirect them back to your site. If you\nprefer, we also provide a popup that you can use. In this method, the authentication happens on a\nseparate popup window and at the end of the auth flow. We recommend that you make the popup send a\nsignal to your main page — using\n[postMessage](https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage) or something\nsimilar — to indicate that the user is logged in. If the popup window fails to open, it'll\nautomatically fall back to the redirect flow. The SDK Example project mentioned above demonstrates\nhow it can work. Again, you can see [sdk-example](https://github.com/schibsted/sdk-example) if you\nwant a working example.\n\n#### Is the user logged in?\n\nSchibsted account relies on browser cookies to determine whether a user is recognized as logged in.\nThe SDK provides functions that can be used to check if the user that's visiting your site is\nalready a Schibsted user or not.\n\n* [Identity#isLoggedIn](https://schibsted.github.io/account-sdk-browser/Identity.html#isLoggedIn)\n  tells you if the user that is visiting your site is already logged in to Schibsted account or not.\n* [Identity#isConnected](https://schibsted.github.io/account-sdk-browser/Identity.html#isConnected)\n  tells you if the user is connected to your client. A user might have `isLoggedIn=true` and at the\n  same time `isConnected=false` if they have logged in to Schibsted account, but not accepted terms\n  and privacy policy for your site.\n\nIf you've lately changed your terms \u0026 conditions, maybe the user still hasn't accepted them. In that\ncase they are considered *not connected*. In that case, if they click \"Log in\" from your site, we\nwill just ask them to accept those terms and redirect them right back to your site.\n\n#### Logging out\n\nIf you want to log the user out of Schibsted account, you can call\n[Identity#logout](https://schibsted.github.io/account-sdk-browser/Identity.html#logout). This\nwill remove the Schibsted account brand session. User will still be logged into Schibsted account.\n\n## Monetization\n\nThe preferred method for checking whether a user has access to a product/subscription is\n[Monetization#hasAccess](https://schibsted.github.io/account-sdk-browser/Monetization.html#hasAccess).\nIt requires using Session Service, and supports both Schibsted account productId's and Zuora\nfeature id's.\n\n#### Example\n```javascript\nimport { Monetization } from '@schibsted/account-sdk-browser'\n\nconst monetization = new Monetization({\n    clientId: '56e9a5d1eee0000000000000',\n    redirectUri: 'https://awesomenews.site', // ensure it's listed in selfservice\n    sessionDomain: 'https://id.aweseome.site', // client-configured session-service domain\n    env: 'PRE', // Schibsted account env. A url or a special key: 'PRE', 'PRO' or 'PRO_NO'\n});\n\ntry {\n    // Check if the user has access to a a particular product\n    const userId = await identity.getUserId();\n    const data = await monetization.hasAccess([productId], userId);\n    alert(`User has access to ${productId}? ${data.entitled}`)\n} catch (err) {\n    alert(`Could not query if the user has access to ${productId} because ${err}`)\n}\n```\n\n## Payment\n\nThis class provides methods for paying with a so-called paylink, buying a product, getting links to\npages for redeeming voucher codes, reviewing payment history, and more.\n\n#### Example\n\n```javascript\nimport { Payment } from '@schibsted/account-sdk-browser'\n\nconst paymentSDK = new Payment({\n    clientId: '56e9a5d1eee0000000000000',\n    redirectUri: 'https://awesomenews.site', // ensure it's listed in selfservice\n    env: 'PRE', // Schibsted account env. A url or a special key: 'PRE', 'PRO' or 'PRO_NO'\n})\n\n// Get the url to paymentSDK with paylink\nconst paylink = '...'\nconst paylinkUrl = paymentSDK.purchasePaylinkUrl(paylink)\n\n// Or another example --- pay with paylink in a popup\npaymentSDK.payWithPaylink(paylink)\n```\n\n## Appendix\n\n#### Polyfills\n\nThis SDK uses modern JavaScript features. If you support older browsers, you should use a tool like\nbabel to transform the JavaScript as needed. However, since certain teams have deployment pipelines\nwhere it's difficult to do their own transpilation, we do provide some opt-in es5 files as well:\n\n1. `@schibsted/account-sdk-browser/es5`: Include both `Identity`, `Monetization` and `Payment`.\n1. `@schibsted/account-sdk-browser/es5/global`: Include both `Identity`, `Monetization` and\n   `Payment`. In addition, add them as variables to the global `window` object.\n1. `@schibsted/account-sdk-browser/es5/identity`, `@schibsted/account-sdk-browser/es5/monetization`\n   or `@schibsted/account-sdk-browser/es5/payment` can be used to only include each class by itself.\n\nBut then regardless of whether you use the es5 versions or not, you might need to polyfill certain\nthings that might be missing in the browsers you wish to support. A quick test using IE11 showed\nthat we needed polyfills for `Promise`, `URL`, `Object.entries`, `fetch`, `Number.isFinite` and\n`Number.isInteger`.\n\n#### Cookies\n\nThere are some cookies used by Schibsted account. They should all be considered opaque on the\nbrowser side. Nevertheless, here is a short description of them.\n\n1. The **autologin** cookie (often called 'the remember-me-cookie'): The cookie name in the\n   production environments is `vgs_email`, because reasons (on PRE, it is called `spid-pre-data`).\n   It's a JSON string that's encoded using the standard `encodeURIComponent()` function and is an\n   object that contains two pieces of information that's important:\n   * `remember`: if set to `true`, the user chose to be remembered and this means we usually support\n     auto-login (that is, if you call the Schibsted account hassession service, and no session can\n     be found in the session database, it will automatically create a new one for the user so that\n     they don't have to authenticate again. If it is `false`, it should be interpreted as the user\n     does not want to be automatically logged in to any site when their session expires\n   * `v`: the version number\n1. The **session** cookies: Cookie names in production environments are `identity`, and `SPID_SE` or\n   `SPID_NO`. It contains:\n   * `user`: an object (if it's missing, a call to hassession will return a `401` with a\n     `UserException` that says `No session found`)\n     * `userId` identifies the user. We use this property to compare \"old\" user with \"new\" user and\n       fire events that indicate that the user has changed\n     * `is_logged_in` indicates if the user is logged in\n   * `user_tags`: a map that contains some flags about the user; namely:\n     * `is_logged_in` indicates if the user is logged in (this seems to be a duplicate of a\n       property with a similar name in the parent `user` object)\n     * `terms`: a map of term ids that indicate if they've been accepted by the user.\n   * `referer` (yep, missing the double \"rr\"..): If this is missing, a call to hassession will\n     return a `401` with a `UserException` that says `No session found`.\n\n## Releasing\nTags are pushed to NPM via Travis. To release a new version, run in master\n\n```bash\n$ npm version \u003cmajor|minor|patch\u003e\n```\n\nwhich will run the test, update version in package.json, commit, tag the commit\nand push.\n\n## LICENSE\n\nCopyright (c) 2024 Schibsted Products \u0026 Technology AS\n\nLicensed under the [MIT\nLicense](https://github.com/schibsted/account-sdk-browser/blob/master/LICENSE.md)\n\nUnless required by applicable law or agreed to in writing, software distributed under the License is\ndistributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\nimplied. See the License for the specific language governing permissions and limitations under the\nLicense.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fschibsted%2Faccount-sdk-browser","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fschibsted%2Faccount-sdk-browser","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fschibsted%2Faccount-sdk-browser/lists"}