This package has been deprecated

Author message:

Package no longer supported. Use one of the certified Relying Party Libraries instead: https://openid.net/developers/certified/#RPLibs

7pass-node-sdk

2.0.1 • Public • Published

7Pass NodeJS SDK

7Pass NodeJS SDK is a JS library for interacting with the 7Pass SSO service. You can use this library to implement authentication for your website and take advantage of the already existing features that 7Pass SSO offers.

Installation

To install the package, run the following:

npm install 7pass-node-sdk

Running the example application

To demonstrate the functionality of the library, there's an interactive tutorial / guide available. Before we get started setting it up, you need your web application's client. The client represents the entity which is associated with a service you want to authenticate to.

To obtain the client credentials, you first need to contact the 7Pass Tech Team.

Once you have the credentials available, you can go ahead and run the application.

First SDK library dependencies need to be installed:

npm install

Then you go to the example_app directory and install example application dependencies:

cd example_app
npm install

Create the local configuration file:

cp config.local.js.example config.local.js

Edit the config.local.js file in your favorite editor and fill out the details. You should have all of the parameters at your disposal after your client is set up. For testing, keep the environment set to qa. Once that's done, you can start the application:

npm start

The example application should be now available at http://localhost:8000. The application will guide you through the most common use cases of the library and show you code examples and server responses along the way.

API Usage

You strongly encouraged to go over the example application first. It will show you the API calls with more comments and real values. It will also show you the real responses from the 7Pass SSO service as you progress.

To use the library, it's necessary to initialize it with the credentials of the client we want to use. If you don't have the credentials yet, please see above.

  • client_id (required)
  • client_secret (required)

If you're starting the development, it's always a good idea to work against a non live instance of the 7Pass SSO service. To specify the instance (the environment) against which you want to issue the requests, you can pass an additional key called environment to the configuration. There are currently two environments running: QA and production. Don't forget to switch to the production version before you release your application to the public.

var sevenpass = require('7pass-node-sdk');

var config = {
  client_id: 'YOUR_CLIENT_ID',
  client_secret: 'YOUR_CLIENT_SECRET',
  environment: 'qa' // Optional, defaults to 'production'
};

// 1. Create and initialize the configuration object
// Configuration object fetches OpenID Configuration and JWT public key endpoints
sevenpass.Configuration.createAndInit(config, function(err, ssoConfig) {
  if(err) {
    throw err;
  }

  // 2. Create 7Pass SSO object passing initialized Configuration object
  var sso = new sevenpass.SSO(ssoConfig);

  //your app code continues here.
});

For both environments there is a default host URL where 7Pass API endpoints can be reached on. For production environment it is https://sso.7pass.de and for qa a host is https://sso.qa.7pass.ctf.prosiebensat1.com. If needed, this can be overwritten by specifying host in the configuration as below:

var config = {
    host: 'https://mysubdomain.7pass.de',
    // ... other config values
};

Authentication flow

The authentication process is simple and the high level view is as follows: The user is redirected to the 7Pass SSO service using a specially crafted URL and he/she signs in (or signs up). Once the user has finished the process, he/she is redirected back to your application with a special code in the URL. The application will then use the code in order to get the user's details. The process may vary depending on the passed options.

1. Get a redirect URL

The library automatically handles the generation of the URL to which the user needs to be redirected. The only required parameter is the redirect_uri URL. The URL needs to be absolute and can be arbitrary (given that it is registered to the client) but will by convention lead to the same host and a route called "callback".

Use of state parameter is optional but recommended to avoid CSRF attacks

  • the value is usually stored in the session and is also used with sso.authorization().callback() method when handling the callback request.
options = {
  redirect_uri: 'https://example.com/callback', // Required.
  scope: 'openid profile email', // Optional, default value.
  response_type: 'code' // Optional, default value.
  state: sessionState // Optional, but recommended to avoid CSRF attacks
};

redirectUrl = sso.authorization().authorizeUri(options);

The library will automatically set the client_id and nonce (a unique request identifier) parameters automatically.

2. Redirect an user

Now it's time to redirect the user to the generated URL.

3. Handling 7Pass callback

After the user has finished with the sign in/up dialog, he/she has been redirected to the redirect_uri URL with the outcome of the sign in process. The user might have successfully authenticated but also might have decided to cancel the process or some other error might have happened. Therefore it's important have proper error handling.

Whenever an error occurs, there will be two query parameters present in the URL - error and error_description. The error parameter contains an error code and the error_description contains a human readable description of the error suitable for direct displaying to the user.

You might choose to handle an error manually as below. Otherwise in case of an error, sso.authorization().callback() callback receives AuthorizeCallbackException error.

// 1. Check if query params contain callback error
if(queryParams.error) {
  var error = queryParams.error;
  var errorDescription = queryParams.error_description;

  // 2. Handle the error and display appropriate message to your end-user.
}

The library handles retrieving the tokens on its own, you just need to provide the redirect_uri and also query parameters from the request. This allows you to retrieve the tokens which can be used to fetch the actual information about the user later. These tokens are specific to the particular user and are private. You need to keep them secured and do not share them with anybody.

sessionState parameter is optional but same should be provided if used with sso.authorization().authorizeUri() method. AuthorizeCallbackException callback error is received when state value provided and the one retrieved from query parameters do not match.

// queryParams variable below contains query parameters from the current URL

// 1. Request access token
sso.authorization().callback(callbackUri, queryParams, sessionState, function(err, tokens) {
  if(err) {
    throw err;
  }

  // 2. Store tokens into the user's session storage. You might also want
  //    to store them in your persistent storage (i.e. your database) or
  //    any other storage of your own choosing.
});

The received response will have the following structure. Run the example application to see the real values.

{
  "access_token": ACCESS_TOKEN,
  "token_type": "Bearer",
  "refresh_token": REFRESH_TOKEN,
  "expires_in": 7200,
  "id_token": JWT_STRING,
  "received_at": RECEIVED_AT_TIMESTAMP,
  "id_token_decoded": DECODED_JWT
}

Note: The id_token_decoded value is decoded from the id_token field and verified. If token verification fails, the error is thrown.

4. Caching an access token

The tokens are represented in a single object of type TokenSet. You can now store tokens into the user's session storage. You might also want to store them in your persistent storage (i.e. your database) or any other storage of your own choosing.

Access tokens are valid for certain amount of time specified in seconds in the expires_in field. Once the access token expires, it can no longer be used. You can obtain a new one using the refresh token as follows:

var TokenSet = require('7pass-node-sdk').TokenSet;

function getFreshTokens(callback) {
  // 1. Create TokenSet object - tokensData contains hash of tokens data as retrieved from user's session
  tokens = new TokenSet(tokensData);

  // 2. Check whether the access token has expired and return immediately if not.
  if(!tokens.isAccessTokenExpired()) {
    return callback(null, tokens);
  }

  // 3. Refresh tokens
  sso.authorization().refresh(tokens, function(err, refreshedTokens) {
    if(err) {
      return callback(err);
    }

    // 4. Store the refreshed tokens back into user's session storage.

    // 5. Return fresh tokens
    callback(null, refreshedTokens)
  });
}

getFreshTokens(function(err, tokens) {
  // Now when you made sure tokens are fresh, you can use them further to create API clients.
})

Note: refresh() method above also accepts object like { refresh_token: 'REFRESH_TOKEN' } as an argument.

5. Calling our API endpoints

Now that we're sure the tokens are up to date, we can start making requests to the 7Pass SSO service to get the user data.

Same as with the previous example, run the example application to see the real server response.

// Create a client object using the tokens
var accountClient = sso.accountClient(tokens);

accountClient.get('me', function(err, data) {
  // Handle error

  // 'data' variable contains the response data
});

The 7Pass SSO service offers quite a few of these endpoints. To learn more about them, you can go to the official documentation's overview.

Client Credentials requests

The library supports multiple types of "clients". These clients generally differ in the required configuration parameters and afterwards in the functionality they provide. The "client credentials" client is a special kind of client which is not associated with a user account and can be only used to call the "clients" APIs.

You can see all of the available endpoints in the documentation with the accessType parameter equal to client.

var sevenpass = require('7pass-node-sdk'), sso;

var config = {
  client_id: 'YOUR_CLIENT_ID',
  client_secret: 'YOUR_CLIENT_SECRET',
  environment: 'qa' // Optional, defaults to 'production'
};

// 1. Create and initialize the configuration object
// Configuration object fetches OpenID Configuration and JWT public key endpoints
sevenpass.Configuration.createAndInit(config, function(err, ssoConfig) {
  if(err) {
    throw err;
  }

  // 2. Create 7Pass SSO object passing initialized Configuration object
  sso = new sevenpass.SSO(ssoConfig);

  // 3. Get the tokens using the client credentials grant type
  sso.authorization().clientCredentials(handleClientCredentialsAuthorization);
});

function handleClientCredentialsAuthorization(err, tokens) {
  if(err) {
    throw err;
  }

  // 4. Use the client as you normally would when using the standard access
  var clientCredentialsClient = sso.clientCredentialsClient(tokens);
  clientCredentialsClient.post('checkPassword', {
    password: 'PASSWORD'
  }, function(err, data) {
    //handle response
  });
}

Device flow

With device flow people can easily and safely log into apps and services with their 7Pass account on devices with limited input or display capabilities. This includes Smart TVs, digital photo frames, or Internet of Things devices.

The device (your application) instructs the end-user to use another computer or device and connect to 7Pass to approve the access request. Since your application cannot receive incoming requests, it polls the 7Pass authorization server repeatedly until the end-user completes the approval process.

Your application initiates the flow by requesting a set of verification codes from the authorization server by making an HTTP POST request to the token endpoint.

sso.authorization().deviceCode(function(err, deviceCodeResponse) {
    // handle error
    
    // deviceCodeReponse - see example below
});

deviceCodeResponse would be object like the following:

{
    code: CODE         // used along with poll requests (see below)
    user_code: Q9CFLH  // the code which user should enter on LINK page 
    expires_in: 600    // expiration of the code (in seconds) 
    interval: 5        // recommended interval for repeating poll requests (in seconds)
    link: LINK_URL     // verification URL user should use to authenticate
    link_qr: IMAGE_URL // image URL of QR code encoded link
}

The user should now be prompted to visit link URL on another device to enter user_code. link_qr is URL of an image representing QR code encoded link URL. This could be used by users using mobile devices, they can scan it and have link URL opened in their mobile browsers without manually typing it themselves.

While user tries to authenticate on link URL, your application polls 7Pass server repeatedly. Recommended interval is specified in interval value.

code in the example below can be either deviceCodeResponse object received from sso.authorization().deviceCode() method call, object with code property or simply a string with code value.

// repeat every [interval] seconds.
sso.authorization().deviceCodePoll(code, function(err, response) {
    if (err) {
        // handle the error appropriately
        // if OAuth2 error: err.error is set to one of error codes 'code_expired', 'slow_down', 'invalid_grant'
        return;
    }
    
    // reponse === false in case 'authorization_pending' response is received
    
    if (response !== false) {
        // reponse is TokenSet object
        // stop polling - user has authorized from another device successfully
    }
});

Backoffice requests

The library can also be used to perform "backoffice" requests. These requests are initiated without direct involvement of users and are meant for administrative purposes. Your client needs to have the backoffice_code grant type allowed. You also need to know the ID of the user you want to work with.

Backoffice requests are used to make an API calls on behalf of other users. To get access token for these requests you need to use special grant type 'backoffice_code' providing an account_id. Upon successful authentication you get a same token set as using standard flow described above.

var sevenpass = require('7pass-node-sdk');

var config = {
  backoffice_key: 'YOUR_BACKOFFICE_KEY',
  service_id: 'YOUR_SERVICE_ID',
  environment: 'qa' // Optional, defaults to 'production'
};

// 1. Create and initialize the configuration object
// Configuration object fetches OpenID Configuration and JWT public key endpoints
sevenpass.Configuration.createAndInit(config, function(err, ssoConfig) {
  if(err) {
    throw err;
  }

  // 2. Create 7Pass SSO object passing initialized Configuration object
  var sso = new sevenpass.SSO(ssoConfig);

  // 3. Get the tokens using the backoffice
  sso.authorization().backoffice({
    account_id: 'ACCOUNT_ID' // Required, the ID of the user you want to access
  }, handleBackofficeAuthorization);
});

function handleBackofficeAuthorization(err, tokens) {
  if(err) {
    throw err;
  }

  // 4. Use the client as you normally would when using the standard access
  var aaccountClient = sso.accountClient(tokens);
  accountClient.get('me', function(err, data) {
    //handle response
  });
}

The response will be as usual. Once you get the tokens, the 7Pass SSO service will act as if the access token has been obtained using the "standard" way.

Client/backoffice registration

When you register new users using the client or backoffice registration API, you might want to bounce them to the 7Pass SSO service so that the user's session is created and the user logged in.

This SDK provides a method called autologinUri() which can be used to generate the redirect (bounce) URL. The method accepts a TokenSet as its first parameter. You can retrieve the user's tokens when using the registration API by providing the scope parameter. See the registration API documentation for more details. response_type defaults to none but can be set to any other supported type if needed so.

// client is an instance of ApiClient created using sso.clientCredentialsClient() or sso.backofficeClient() methods.
client.post('registration', {
    scope: 'openid profile email'
    // other parameters
}, function(err, response) {
    //handle error
    
    var tokens = TokenSet.receiveTokens(response);
    
    var uri = sso.authorization().autologinUri(tokens, {
        redirect_uri: callbackUri, // Required
        state: sessionState // Optional but recommended to use
    }, {
        remember_me: true // Default value: false
    });
    
    // Redirect user to uri
});

As with other ordinary authorize requests, you can use sso.authorization().callback() method to handle a callback request. The callback receives null if response_type was set to none.

Running the tests

The library uses mocha for testing.

npm test

Readme

Keywords

none

Package Sidebar

Install

npm i 7pass-node-sdk

Weekly Downloads

4

Version

2.0.1

License

MIT

Unpacked Size

45.8 kB

Total Files

13

Last publish

Collaborators

  • p7s1-ctf