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'
};
sevenpass.Configuration.createAndInit(config, function(err, ssoConfig) {
if(err) {
throw err;
}
var sso = new sevenpass.SSO(ssoConfig);
});
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',
scope: 'openid profile email',
response_type: 'code'
state: sessionState
};
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.
if(queryParams.error) {
var error = queryParams.error;
var errorDescription = queryParams.error_description;
}
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.
sso.authorization().callback(callbackUri, queryParams, sessionState, function(err, tokens) {
if(err) {
throw err;
}
});
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) {
tokens = new TokenSet(tokensData);
if(!tokens.isAccessTokenExpired()) {
return callback(null, tokens);
}
sso.authorization().refresh(tokens, function(err, refreshedTokens) {
if(err) {
return callback(err);
}
callback(null, refreshedTokens)
});
}
getFreshTokens(function(err, tokens) {
})
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.
var accountClient = sso.accountClient(tokens);
accountClient.get('me', function(err, 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'
};
sevenpass.Configuration.createAndInit(config, function(err, ssoConfig) {
if(err) {
throw err;
}
sso = new sevenpass.SSO(ssoConfig);
sso.authorization().clientCredentials(handleClientCredentialsAuthorization);
});
function handleClientCredentialsAuthorization(err, tokens) {
if(err) {
throw err;
}
var clientCredentialsClient = sso.clientCredentialsClient(tokens);
clientCredentialsClient.post('checkPassword', {
password: 'PASSWORD'
}, function(err, data) {
});
}
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'
};
sevenpass.Configuration.createAndInit(config, function(err, ssoConfig) {
if(err) {
throw err;
}
var sso = new sevenpass.SSO(ssoConfig);
sso.authorization().backoffice({
account_id: 'ACCOUNT_ID'
}, handleBackofficeAuthorization);
});
function handleBackofficeAuthorization(err, tokens) {
if(err) {
throw err;
}
var aaccountClient = sso.accountClient(tokens);
accountClient.get('me', function(err, data) {
});
}
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.post('registration', {
scope: 'openid profile email'
}, function(err, response) {
var tokens = TokenSet.receiveTokens(response);
var uri = sso.authorization().autologinUri(tokens, {
redirect_uri: callbackUri,
state: sessionState
}, {
remember_me: true
});
});
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