auth0/auth0-guardian.js

Name: auth0-guardian.js

Owner: Auth0

Description: Client library for Auth0 Guardian

Created: 2016-08-15 02:14:05.0

Updated: 2018-05-12 13:05:04.0

Pushed: 2018-04-20 18:00:36.0

Homepage: https://auth0.com/guardian

Size: 2400

Language: JavaScript

GitHub Committers

UserMost Recent Commit# Commits

Other Committers

UserEmailMost Recent Commit# Commits

README

auth0-guardian-js Build Status

UI-less client for Guardian.

Installation
install auth0-guardian-js
CDN

Full version

s://cdn.auth0.com/js/guardian-js/1.3.0/guardian-js.js

Minified version

s://cdn.auth0.com/js/guardian-js/1.3.0/guardian-js.min.js
Basic Usage
Configuration
auth0GuardianJS = require('auth0-guardian-js')({
// For US tenants: https://{name}.guardian.auth0.com
// For AU tenants: https://{name}.au.guardian.auth0.com
// For EU tenants: https://{name}.eu.guardian.auth0.com
serviceUrl: "https://{{ userData.tenant }}.guardian.auth0.com",
requestToken: "{{ requestToken }}", // or ticket: "{{ ticket }}" - see below

issuer: {
    // The issuer name to show in OTP Generator apps
    label: "{{ userData.tenantFriendlyName }}",
    name: "{{ userData.tenant }}",
},

// The account label to show in OTP Generator apps
accountLabel: "{{ userData.friendlyUserId }}",

// Optional, for debugging purpose only,
// ID that allows to associate a group of requests
// together as belonging to the same "transaction" (in a wide sense)
globalTrackingId: "{{ globalTrackingId }}"

Use of requestToken or ticket depends on the authentication method. Ticket corresponds to a previously generated enrollment ticket.

Enrollment

To enroll a device is a process composed of the following steps:

  1. Start the transaction

  2. (optional) Check if the user is already enrolled. You cannot enroll twice.

  3. Send the information needed to enroll

  4. Confirm your enrollment

  5. Show the recovery code

  6. Some steps can be omited depending on the method, we provide the same interface for all methods so you can write uniform code.

  7. Some of the methods end up completing the authentication, whereas some others need an extra authentication step. You can know that by listening to the enrollment-complete event.

tion enroll(transaction, method) {
if (transaction.isEnrolled()) {
    console.log('You are already enrolled');
    return;
}

var enrollData = {};

if (method === 'sms') {
    enrollData.phoneNumber = prompt('Phone number'); // Collect phone number
}

return transaction.enroll(method, enrollData, function (err, otpEnrollment) {
    if (err) {
        console.error(err);
        return;
    }

    var uri = otpEnrollment.getUri();
    if (uri) {
        showQR(uri);
    }

    var confirmData = {};
    if (method === 'otp' || method === 'sms') {
        confirmData.otpCode = prompt('Otp code'); // Collect verification otp
    }

    otpEnrollment.confirm(confirmData);
});


0GuardianJS.start(function(err, transaction) {
if (err) {
    console.error(err);
    return;
}

transaction.on('error', function(error) {
    console.error(error);
});

transaction.on('timeout', function() {
    console.log('Timeout');
});

transaction.on('enrollment-complete', function(payload) {
    if (payload.recoveryCode) {
        alert('Recovery code is ' + payload.recoveryCode);
    }

    if (payload.authRequired) {
        showAuthenticationFor(transaction, payload.enrollment);
        return;
    }
});

transaction.on('auth-response', function(payload) {
    if (payload.recoveryCode) {
        alert('The new recovery code is ' + payload.recoveryCode);
    }

    if (!payload.accepted) {
        alert('Authentication has been rejected');
        return;
    }

    auth0GuardianJS.formPostHelper('{{ postActionURL }}', { signature: payload.signature });
});

var availableEnrollmentMethods = transaction.getAvailableEnrollmentMethods();

method = prompt('What method do you want to use, select one of '
    + availableEnrollmentMethods.join(', '));

enroll(transaction, method) // For sms

Authentication

To authenticate with a method you need to execute the following steps

  1. Start the transaction
  2. (optional) Check if the user is already enrolled. You need to be enrolled to authenticate.
  3. Request the auth (the push notification / sms). Request is a noop for OTP
  4. Verify the otp (.verify is a noop for push)

Some steps can be omitted depending on the method, we provide the same interface for all methods so you can write uniform code. After the factor is verified or the push accepted you will receive an auth-response event with the payload to send to the server, you can use the auth0GuardianJS.formPostHelper('{{ postActionURL }}', payload) to post back the message to the server.

You may also receive auth-rejected if the push notification was received.

tion authenticate(method) {
auth0GuardianJS.start(function (err, transaction) {
    if (err) {
        console.error(err);
        return;
    }

    if (!transaction.isEnrolled()) {
        console.log('You are not enrolled');
        return;
    }

    transaction.on('error', function(error) {
        console.error(error);
    });

    transaction.on('timeout', function() {
        console.log('Timeout');
    });

    transaction.on('auth-response', function(payload) {
        if (payload.recoveryCode) {
            alert('The new recovery code is ' + payload.recoveryCode);
        }

        if (!payload.accepted) {
            alert('Authentication has been rejected');
            return;
        }

        auth0GuardianJS.formPostHelper('{{ postActionURL }}', { signature: payload.signature });
    });

    var enrollment = transaction.getEnrollments()[0];

    if (enrollment.getAvailableAuthenticatorTypes().length === 0) {
        alert('Somethings went wrong, seems that there is no authenticators');
        return;
    }

    transaction.requestAuth(enrollment, { method: method } function(err, auth) {
        if (err) {
            console.error(err);
            return;
        }

        var data = {};
        if (method === 'sms' || method === 'otp') {
            data.otpCode = prompt('Otp code');
        } else if (method === 'recovery-code') {
            data.recoveryCode = prompt('Recovery code');
        }

        return auth.verify(data);
    });
});

Recovery

DEPRECATED: This method has been deprecated and its usage is discouraged, use .requestAuth with method recovery-code (if available) instead.

Recovery works as authentication, but instead of passing an otpCode, you need to pass a recoveryCode to verify method

0GuardianJS.start(function(err, transaction) {
if (err) {
    console.error(err);
    return;
}

transaction.on('error', function(error) {
    console.error(error);
});

transaction.on('timeout', function() {
    console.log('Timeout');
});

transaction.on('auth-response', function(payload) {
    if (payload.recoveryCode) {
        alert('The new recovery code is ' + payload.recoveryCode);
    }

    if (!payload.accepted) {
        alert('Authentication has been rejected');
        return;
    }

    auth0GuardianJS.formPostHelper('{{ postActionURL }}', { signature: payload.signature });
});

if (!transaction.isEnrolled()) {
    console.log('You are not enrolled');
    return;
}

var recoveryData = {};
recoveryData.recoveryCode = prompt('Recovery code'); // Collect recovery code

return transaction.recover(recoveryData);

Full API

First of all you need to instantiate the library

t auth0GuardianJS = require('auth0-guardian-js')({
requestToken: //...,
serviceUrl: //...,
issuer: {
    name: //...,
    label: //...
},
accountLabel: //...

auth0GuardianJS.start(callback)

Starts a transaction on Guardian, callbacks with an error (if any) or a transaction ready to be used.

A transaction holds the current state of the operations being executed in Guardian and provides a bound point to listen to events and execute further operations.

0GuardianJS.start(function(err, transaction) {
...

auth0GuardianJS.resume(options, transactionState, callback)

This continues a transaction saved by transaction.serialize(). The options parameter provides the library user the opportunity to specify which kind of transport to use. Options include:

If not set, the socket transport is used as default

This is a factory method, you SHOULD NOT instantiateauth0GuardianJS.

at some point in your code you stored the transaction:

0GuardianJS.start(function(err, transaction) {
...

cureStorage.store('guardiantx', transaction.serialize());

Later, in another part of the code:

serializedTransaction = secureStorage.get('guardiantx');

0GuardianJS.resume({ transport: 'polling' }, serializedTransaction, function(err, transaction) {
... continue using that transaction object.

Transaction
transaction.isEnrolled()

Returns true if user is already enrolled, false otherwise.

saction.isEnrolled();
transaction.getAvailableEnrollmentMethods()

Returns an array of strings that represent the available enrollment methods, they are the methods that are currently available for you to enroll with.

The supported methods right now are:

saction.getAvailableEnrollmentMethods();
transaction.getAvailableAuthenticationMethods()

DEPRECATED: Use .getAvailableAuthenticatorTypes() from the enrollment instead.

Returns an array of strings that represent the available authentication methods, they are the methods that are currently available for you to authenticate with.

The supported methods right now are:

saction.getAvailableAuthenticationMethods();
transaction.getEnrollments()

Returns an array current user's enrollments objects, right now it will return single enrollment if user is enrolled, or no enrollment is user is not enrolled.

enrollments = transaction.getEnrollments();
transaction.enroll(data, callback)

Starts an enrollment, this method is only valid when the user is not enrolled and there is at least an enrollment method available; otherwise it will return an error. It receives the data needed to enroll which is different depending on the method you want to use (see below) and callbacks with an error if it has been rejected or an enrollmentFlow if it has been accepted.

Enrollment data:

data = // Depends on the method
ata.phoneNumber for sms
he other methods don't require extra data

saction.enroll(data, function(err, enrollmentFlow) {


transaction.requestAuth(enrollment, [{ method: string }], callback)

Starts authentication, this method is only valid if user is enrolled and there is at least one authentication method available for this transaction and the enrollment (otherwise, will callback with an error). It receives the enrollment and optionally the method you want to enroll (otherwise the first one available on the enrollment will be used) and callbacks with an error or the authFlow. As result of this methods auth-response or error could be triggered.

saction.requestAuth(enrollments[0], { method: enrollment.getAvailableMethods()[0] }, function(err, authFlow) {
if (err) {
    // ...
}

var data = // otpCode for sms or otp; none for push
authFlow.verify(data)

transaction.recover({ recoveryCode: string })

DEPRECATED: This method has been deprecated and its usage is discouraged, use .requestAuth with method recovery-code (if available) instead.

Authenticates using a recovery code, receives the recovery code as an string with just alpha numeric characters (no separators, etc.) as result of this method an error or auth-response error could be emitted; in case of auth-response it will include .recoveryCode as part of the payload, that recovery code is the new recovery code you must show to the user from him to save it.

saction.recover({ recoveryCode: recoveryCode });
transaction.serialize()

The .serialize() method creates a plain javascript Object that should remain opaque to the library user. This must be stored by the user in a secure way.

This object is used in combination with auth0GuardianJS.resume

transaction.on(eventName, handler)

Listen for eventName and execute the handler if that event is received. The handler might include a payload with extra information about the event.

Events enrollment-complete

Emitted when the enrollment has been completed; you could receive this event even when you have not started an enrollment from this transaction. In such case recoveryCode won't be available and it means that enrollment has been completed in a different transaction (for example in another tab), you should show authentication (authRequired will be true).

saction.on('enrollment-complete', function ({ authRequired, recoveryCode, enrollment }) {
// Enrollment confirmed

// authRequired will be true if the enrollment methods require authentication

// recoveryCode will be available only in case that the enrollment has been started from
// the current transaction, you should show it for the user to write it down.

// enrollment the shinny new enrollment, use it to authenticate if authRequired
// is true

auth-response

Emitted when an authentication have been accepted or rejected. SMS and OTP enrollments also trigger this event since after those enrollments you are assumed to be authenticated; push enrollment doesn't trigger it and you should start the normal auth flow instead after enrollment. If there is an active enrollment in the current transaction, auth-response is guaranteed to be triggered after enrollment-complete.

saction.on('auth-response', function({ accepted, recoveryCode, signature }) {
// Auth response
//
// accepted: true if the authentication has been accepted, false otherwise
//
// signature: data to post to the verifier server for it to verify the transaction
//  it is only available if the transaction has been accepted
//
// recoveryCode: only available after recovery, it is the new recovery code the
// user should save securely.

timeout

Emitted when the transaction is no longer valid, you cannot enroll or authenticate. You should start a new transaction.

transaction.on('timeout', function () {

// Transaction time out

});

error

Emitted when there is an error on the transaction

saction.on('error', function(error /* instanceOf GuardianError */) {
// Errors that cannot be associated to a particular action, like socket.io errors or so

EnrollmentFlow

Let you confirm and execute operations on a not-yet-confirmed enrollment.

enrollmentFlow.getUri()

Returns the enrollment URI for methods that support uri-based enrollments (push and otp), this URI is usually presented as a QR code. It is a noop that returns null for for methods that don't support URI-based enrollment.

enrollmentFlow.getData()

Returns the enrollment data for methods that to transfer some data between devices in order to enroll (such as push and otp). This data could be used to generate the enrollment uri to show in a QR but since this is a common use case we provide enrollmentFlow.getUri() as a convenience method. The main use case for this data is when you want to use a different way to transfer the data instead of a QR code. For methods that don't need to transfer any data (such as sms) it is a noop that returns null.

The data includes the following fields:


suerLabel: // Issuer label
pSecret: // Base 64 encoded otp secret
rollmentTransactionId: // Transaction id to start enrollment exchange
suerName: // Issuer 'unique' name
rollmentId: // Id of current enrollment (pending confirmation)
seUrl: // Base url for mobile app
gorithm: // Algorithm for otp generation
gits: // Number of digits for otp generation
unter: // Counter for otp generation
riod: // Duration of each otp code

enrollmentFlow.confirm(data)

Confirms the enrollment, an enrollment is not considered valid until it is confirmed the data needed to confirm the enrollment depends on the method (see below). As result of this method, error or enrollment-complete events can be fired.

Enrollment confirmation data:

Auth Flow
authFlow.verify(data)

Let you verify the authentication by providing the verification data (see below). Push notfication does need this because the confirmation is done on the cell phone.

Auth verification data:

authFlow.getMethod()

Returns the method associated with current auth flow; it might be sms, otp or push.

Enrollment
enrollment.getAvailableMethods()

DEPRECATED: Use .getAvaialbeAuthenticatorTypes instead. This method does not includes recovery authenticator which has become its own specific authenticator type.

Returns an array of strings that represent the authentication methods that can be used for this enrollment in the current transaction (the available methods might change from transaction to transaction). They depends on the methods supported by the enrollment and the methods currently allowed by the tenant.

llments[i].getAvailableMethods();
enrollment.getMethods()

Returns an array of strings that represent the authentication methods associated with this enrollments, they are the only methods that (if available for this transaction) can be used to authenticate the user based on the given enrollment.

llments[i].getMethods();
enrollment.getAvailableAuthenticatorTypes()

Returns an array of strings that represent the authenticator types (that used to be called methods) that can be used for this enrollment in the current transaction (the available types might change from transaction to transaction). They depend on the types supported by the enrollment and the methods currently allowed by the tenant.

enrollment.getName()

Returns the device name associated with the enrollment, this is a name you can show to the user; and it might be used to identify the device in an user-friendly way. This name is only available for push notification enrollments.

enrollment.getPhoneNumber()

Returns the phone number associated with the enrollment. This number will be masked and it is only meant to be used as a way for the user to identify the device that will receive the SMS.

Error object and error codes

Every error you can get from the api (callback error or error event) is an instance of Error and have the following format:


message: string, // English message, description of the error
errorCode: string // Unique identifier or the error
statusCode: number // For http requests: http status code

Error codes

The error codes may (and should) be used to display informative messages and to distinguish between recoverable and unrecoverable errors. This is a list of the errors codes and its meaning

| Error Code | Description | |————|————-| | invalid_token | Invalid request or transaction token | | insufficient_scope | You don't have enought grants to perform the requested operation | | invalid_bearer_format | The bearer put in authentication header was not valid | | enrollment_conflict | There is another enrollment for the same user. You cannot enroll twice. | | tenant_not_found | The tenant associated cannot be found. Should not normally hapen at least that you delete the tenant | | login_transaction_not_found | The mfa auth transaction is not active or has already expired | | error_sending_push_notification | Push notification delivery failed | | push_notification_wrong_credentials | Push notification delivery failed because of wrong credentials | | invalid_otp | Provided otp code was not valid | | invalid_recovery_code | Provided recovery code was not valid | | invalid_body | Body validation failed. Bad request. | | invalid_query_string | Query string validation failed. Bad request. | | enrollment_transaction_not_found | The mfa enrollment transaction is not active or has expired | | invalid_phone_number | The provided phone number is invalid | | error_sending_sms | SMS Delivery error | | feature_disabled | The requested feature is currently globally not available (contact the provider) | | feature_disabled_by_admin | The requested feature is currently disabled by your admin | | pn_endpoint_disabled | We were unable to deliver the push notification after retrying many times. Try removing you account for the device and adding it again. | | too_many_sms | You have exeed the amount of SMSs assigned to your user | | too_many_pn | You have exeed the amount of push notifications assigned to your user | | too_many_sms_per_tenant | You have exeed the amount of SMSs assigned to your tenant | | too_many_pn_per_tenant | You have exeed the amount of push notifications assigned to your tenant | | field_required | A field is required to perform the operation (this errors has a field attribute with a code for the field: otpCode, recoveryCode) | | method_not_found | You have requested a method that is currently not supported (should not happen) | | no_method_available | There is currently no method to enroll (all of them are disabled) | | enrollment_method_disabled | The specified enrollment method is disabled, this error has also a .method field | | auth_method_disabled | The specified authentication method is disabled, this error has also a .method field | | invalid_otp_format | Otp format validation error | | invalid_recovery_code_format | Recovery code format validation error | | transaction_expired | The transaction has already expired | | already_enrolled | You are already enrolled, cannot enroll again | | not_enrolled | You not enrolled. Must enroll first | | invalid_enrollment | The enrollment provided to transaction#requestAuth method is not valid or is null/undefined |


This work is supported by the National Institutes of Health's National Center for Advancing Translational Sciences, Grant Number U24TR002306. This work is solely the responsibility of the creators and does not necessarily represent the official views of the National Institutes of Health.