# ssohelper

> ssohelper is a helper library for setting up a single sign on with jwt in a multi domain environment in no time.

Latest version **1.2.6** (published 2018-07-12) · ISC license · 0 weekly downloads

> **Deprecated.** This package is deprecated.

## Install

```sh
npm install ssohelper
pnpm add ssohelper
yarn add ssohelper
bun add ssohelper
```

## Health

**Score 10/100 (F)** — status: deprecated.

Negative: deprecated.

## Facts

| | |
|---|---|
| Version | 1.2.6 |
| Published | 2018-07-12 |
| First published | 2018-06-25 |
| Weekly downloads | 0 |
| License | ISC |
| TypeScript types | none |
| Module format | CommonJS |
| Dependencies | 38 |
| Unpacked size | 28 KB |
| Known vulnerabilities | 0 (+1 in 1 direct dependencies) |
| Install scripts | no |
| Maintainers | vielhuber |

## Links

- npm: https://www.npmjs.com/package/ssohelper
- npm.io page: https://npm.io/package/ssohelper

## Dependencies (38)

- [vue](https://npm.io/package/vue.md) ^2.5.16
- [gulp](https://npm.io/package/gulp.md) ^3.9.1
- [jest](https://npm.io/package/jest.md) ^23.2.0
- [uglify](https://npm.io/package/uglify.md) ^0.1.5
- [babelify](https://npm.io/package/babelify.md) ^8.0.0
- [jest-cli](https://npm.io/package/jest-cli.md) ^23.1.0
- [gulp-jest](https://npm.io/package/gulp-jest.md) ^4.0.2
- [gulp-sass](https://npm.io/package/gulp-sass.md) ^4.0.1
- [puppeteer](https://npm.io/package/puppeteer.md) ^1.5.0
- [babel-core](https://npm.io/package/babel-core.md) ^6.26.3
- [browserify](https://npm.io/package/browserify.md) ^16.2.2
- [gulp-babel](https://npm.io/package/gulp-babel.md) ^7.0.1
- [ismobilejs](https://npm.io/package/ismobilejs.md) ^0.4.1
- [gulp-concat](https://npm.io/package/gulp-concat.md) ^2.6.1
- [gulp-rename](https://npm.io/package/gulp-rename.md) ^1.2.3
- [gulp-uglify](https://npm.io/package/gulp-uglify.md) ^3.0.0
- [gulp-vueify](https://npm.io/package/gulp-vueify.md) 0.0.3
- [browser-sync](https://npm.io/package/browser-sync.md) ^2.24.4
- [gulp-connect](https://npm.io/package/gulp-connect.md) ^5.0.0
- [gulp-htmlmin](https://npm.io/package/gulp-htmlmin.md) ^4.0.0
- [run-sequence](https://npm.io/package/run-sequence.md) ^2.2.1
- [through-gulp](https://npm.io/package/through-gulp.md) ^0.5.0
- [vinyl-buffer](https://npm.io/package/vinyl-buffer.md) ^1.0.0
- [babel-runtime](https://npm.io/package/babel-runtime.md) ^6.26.0
- [babel-polyfill](https://npm.io/package/babel-polyfill.md) ^6.26.0
- [gulp-clean-css](https://npm.io/package/gulp-clean-css.md) ^3.9.4
- [gulp-penthouse](https://npm.io/package/gulp-penthouse.md) ^0.2.0
- [jest-puppeteer](https://npm.io/package/jest-puppeteer.md) ^3.2.1
- [gulp-sourcemaps](https://npm.io/package/gulp-sourcemaps.md) ^2.6.0
- [babel-preset-env](https://npm.io/package/babel-preset-env.md) ^1.7.0
- [gulp-autoprefixer](https://npm.io/package/gulp-autoprefixer.md) ^5.0.0
- [vueify-insert-css](https://npm.io/package/vueify-insert-css.md) ^1.0.0
- [babel-preset-es2015](https://npm.io/package/babel-preset-es2015.md) ^6.24.1
- [babel-preset-es2017](https://npm.io/package/babel-preset-es2017.md) ^6.24.1
- [vinyl-source-stream](https://npm.io/package/vinyl-source-stream.md) ^2.0.0
- [babel-plugin-array-includes](https://npm.io/package/babel-plugin-array-includes.md) ^2.0.3
- [babel-plugin-transform-runtime](https://npm.io/package/babel-plugin-transform-runtime.md) ^6.23.0
- [babel-plugin-transform-object-rest-spread](https://npm.io/package/babel-plugin-transform-object-rest-spread.md) ^6.26.0

## Recent versions

- 1.2.6 (latest) — 2018-07-12
- 1.2.5 — 2018-07-11
- 1.2.4 — 2018-07-11
- 1.2.3 — 2018-07-11
- 1.2.2 — 2018-06-27
- 1.2.1 — 2018-06-27
- 1.2.0 — 2018-06-27
- 1.1.8 — 2018-06-27
- 1.1.7 — 2018-06-27
- 1.1.6 — 2018-06-27
- 1.1.5 — 2018-06-27
- 1.1.4 — 2018-06-27
- 1.1.3 — 2018-06-27
- 1.1.2 — 2018-06-27
- 1.1.1 — 2018-06-27
- … 8 more at https://npm.io/package/ssohelper/versions

## README

# 🗝️ ssohelper 🗝️

ssohelper is a helper library for setting up a single sign on with jwt in a multi domain environment in no time.

## features

- syncs cookies via iframes through postmessage
- works in all js applications
- renders a simple loginform if needed
- the auth server remains untouched
- has a fetch helper function for api calls that do all the heavy lifting (e.g. refreshing token, repeating calls) under the hood
- provides a fallback for clients that have third party cookies disabled
- includes a timeouts for broken connections

## requirements

- a fully setup jwt auth server with the following routes
  - /login (email, password)
  - /logout
  - /refresh
  - /check (access_token)

## installation

deploy the helper file [ssohelper.html](https://github.com/vielhuber/ssohelper/blob/master/_dist/ssohelper.html) in the root public directories of all pages that use sso. don't forget to fill out all origin page domains in line 7.

then install the javascript module:
```bash
npm install ssohelper
```
```js
import ssohelper from 'ssohelper';
```

you also can embed it in legacy applications like this:
```html
<script src="ssohelper.js"></script>
```

now instantiate the object with the basic configuration:
```js
const sso = new ssohelper({
    auth_server: 'http://example-auth-server.local',
    pages: [
        'http://example-auth-page1.local',
        'http://example-auth-page2.local',
        'http://example-auth-page3.local'
    ],
    login_form_container: '#app'
});
```

## usage

```js
// this function
// ...checks if the user is logged in
// ...tries to generate a new token if possible
// ...if nothing works, renders a login form inside document.body
// ...on submit logs the user in on all pages
sso.login().then(() => { alert('logged in everywhere!'); })

// check if logged in
if( sso.isLoggedIn() ) { }

// get jwt data
sso.getPayload()
sso.getUserId()

// make ajax calls via fetch
// access tokens are automatically refreshed if needed and the request then is called again
// if the user is not logged in and a new token cannot be generated,
// a login form is rendered and after a succesful login, the request is again repeated
// fetch has the same interface as the official javascript Fetch API
sso.fetch('http://example-auth-page1.local/protected/')
sso.fetch('http://example-auth-page2.local/protected/', {
    method: 'POST',
    body: JSON.stringify({ 'foo': 'bar' }),
    cache: 'no-cache',
    headers: { 'content-type': 'application/json' }
}).then(res => res.json()).catch(err => err).then(response => { console.log(response); })

// this function logs out on all pages
sso.logout().then(() => { alert('logged out everywhere!'); })
```

## backend validation

you can easily check inside a backend on another page via php, if the provided access token is valid without even contacting the auth server.

#### installation

```bash
composer require firebase/php-jwt
```

#### index.php
```php
require_once(__DIR__.'/vendor/autoload.php');
use \Firebase\JWT\JWT;

// cors
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: GET, POST, PUT, PATCH, DELETE, OPTIONS');
header('Access-Control-Allow-Headers: Content-Type, Authorization');
if(@$_SERVER['REQUEST_METHOD'] == 'OPTIONS') { die(); }

try
{
    $user_id = JWT::decode(
        str_replace('Bearer ','',@$_SERVER['HTTP_AUTHORIZATION']), // access token
        'WM38tprPABEgkldbt2yTAgxf2CGstfr5', // secret key
        ['HS256']
    )->sub;
    http_response_code(200);
    echo json_encode([
        'success' => true,
        'data' => [
            'id' => $user_id,
            'foo' => 'bar'
        ]
    ]);
    die();
}
catch(Exception $e)
{
    http_response_code(401);
    echo json_encode([
        'success' => false,
        'message' => 'unauthorized',
        'public_message' => '...'
    ]);
    die();
}
```

#### .htaccess
```.htaccess
RewriteEngine On
RewriteCond %{HTTP:Authorization} ^(.*)
RewriteRule .* - [e=HTTP_AUTHORIZATION:%1]
```

## testing

setup the following vhosts:
- http://example-auth-server.local => jwt auth server
- http://example-auth-page1.local => _tests/page1
- http://example-auth-page2.local => _tests/page2
- http://example-auth-page3.local => _tests/page3

and then run the test:
```bash
gulp js-test
```

## pseudo code

- if pageX wants to check if user is logged in on client side (without a backend call)
    - pageX frontend checks if access_token is present in cookie and can be decoded (the token is not validated and it also can be expired)
        - if no, the user is considered to be logged out
        - if yes, the user is considered to be logged in
- if a logged in user makes an backend/api call on pageX
    - pageX frontend checks if access_token is present in cookie and can be decoded (the token is not validated and it also can be expired)
        - if no, the user is considered to be not logged in
            - see login procedure
            - the call is repeated automatically after a succesful login
        - if yes, the user is considered to be logged in
            - the user sets the access_token in the header ("Bearer")
            - pageX backend validates the access token with the secret key
                - if the validation is ok
                    - the backend extracts the user id from the token and uses that to provide data
                    - the final response is served to the client
                - if the validation is not ok
                    - an error is served to the client
                    - the client tries to generate a new token from the old one
                        - if that was successful
                            - pageX sets cookie for oneself
                            - if user has enabled third party cookies                            
                                - pageX server sets new access token in cookie via iframes for all other pages
                            - the call will be repeated automatically
                        - if that was not successful
                            - see login procedure
                            - the call is repeated automatically after a succesful login
- login procedure
    - pageX frontend verifies the access_token via secret_key via the /check route
        - if available and not expired
            - pageX sets cookie for oneself
            - if user has enabled third party cookies
                - pageX server sets new access token in cookie via iframes for all other pages
        - if available and expired
            - pageX frontend tries to generate a new token from old token via the /refresh route
                - if it worked
                    - pageX sets cookie for oneself
                    - if user has enabled third party cookies                
                        - pageX server sets new access token in cookie via iframes for all other pages
                - if it didn't work
                    - render login form
        - if not available
            - render login form
- if the user submits the rendered login form on pageX
    - pageX gets back access token from auth server
    - pageX sets cookie for oneself
    - if user has enabled third party cookies
        - pageX sets cookie via iframes for all other pages
- if the user calls the logout function on pageX
    - pageX calls auth server to logout (this invalidates the token on the server side)
    - pageX removes cookie for oneself
    - if user has enabled third party cookies
        - pageX removes cookie via iframes for all other pages

---
_Source: https://npm.io/package/ssohelper · Machine-readable twin of the npm.io package page. Health data is recomputed on every publish._
