Node module for bulding Apps for A2P3 Proof of Concept



npm module for A2P3

##Quick Install

  1. Register as a user

  2. Create a CLI Agent at Setup and save the device value

  3. npm install a2p3

  4. cd node_modules/a2p3

  5. Edit the config.json file and edit the device, appID and name for as appropriate

  6. npm run-script register

##Installation Details

When installed, a default config.json file is created in node_modules/a2p3 if one does not already exist. This file shold be copied up into your application directory and the device parameter must be inserted.

The register.js script will use the values in config.json to register the app with appID and name at the Registrar, and registers the app at the configured resources (defaults to all resource servers - Email, SI, Health and People) and saves all the keys and key IDs into vault.json. See the vault.json section for more details. You should keep the contents of your vault.json file secret!

A config.json file configures how register.js will generate the vault.json file, and configures a2p3. Looked at the register.js source to see other defaults that can be changed for more complex development environments.

{ "appID":  "app.example.com"       // App hostname
, "name":   "Example App"                   // App friendly name
, "device": "NQLKKnfIc3RbY4a2JRwP"  // CLI Agent device parameter
, "port":   8080                              // port server will listen on
, "resources":
    [ "email.a2p3.net"              // array of resource hostnames
    , "people.a2p3.net"             // to register App at
    , "people.a2p3.net"             // only resources hosted at *.a2p3.net are supported
    , "health.a2p3.net"

####vault.json A vault.json file has the keys and key IDs for the Identifier Exchange (obtained when registering the App at the Registrar) and for any Resource Server. Here is a sample file:

{ "ix.a2p3.net":
  { "latest":
    { "key": "iNW4SL_ks2Xieg558G8Mdm8l9ZmEporVplmNhYosaHbPOypvCfv5BgUWmJkbn4kyjAHcZbuEUacyJs18iAJ2wQ"
    , "kid": "o3dPbnKnz07MxRaL"
  , "o3dPbnKnz07MxRaL": "iNW4SL_ks2Xieg558G8Mdm8l9ZmEporVplmNhYosaHbPOypvCfv5BgUWmJkbn4kyjAHcZbuEUacyJs18iAJ2wQ"
, "email.a2p3.net":
  { "latest":
    { "key": "oncJcWL9CMR6TPYqZOuAh7RCCHe3qyxNNVa5jCWc49zEhTxigBJMnOBYtKUaufeZwotr7ImB8-alEBiOQwi8Jg"
    , "kid": "PhT9eyZqhOfN_Fvg"
  , "PhT9eyZqhOfN_Fvg": "oncJcWL9CMR6TPYqZOuAh7RCCHe3qyxNNVa5jCWc49zEhTxigBJMnOBYtKUaufeZwotr7ImB8-alEBiOQwi8Jg"
, "si.a2p3.net":
  { "latest":
    { "key": "bxnnnJyKrFy02Wam8yHI0NI3nxW8KK2J6M7Jd23PldZ38NV2JiRHSCplR-WNk7oGHS6-U-AxC-q8bVz3MBMyDQ"
    , "kid": "1jL2NNFCS44MXm0d"
  , "1jL2NNFCS44MXm0d": "bxnnnJyKrFy02Wam8yHI0NI3nxW8KK2J6M7Jd23PldZ38NV2JiRHSCplR-WNk7oGHS6-U-AxC-q8bVz3MBMyDQ"

The easy way to generate a vault.json file is to use the register.js script.

If you change the appid or resources in your config.json file, you can generate a new vault.json file

node node_modules\a2p3\setup\register.js config.json

This assumes config.json is in the current directory. This command will generate a new vault.json file in the current directory for you assuming all went well.

##App API Documentation

####agentRequest( config, vault, params )

Creates an Agent Request using the values in config, vault and the supplied params object with the following properties:

  • returnURL or callbackURL: where the Agent will return results for the Agent Request. If returnURL, the Agent will send back results via a redirected GET. If callbackURL, the Agent will POST the results to the URL as a JSON message. REQUIRED.

  • resources: an array of resources the application would like authorization from the User to access. OPTIONAL

var a2p3 = require('a2p3')
  , config = require('./config.json')
  , vault = require('./vault.json')
  , params =
    { returnURL = 'http://localhost:8080'
    , resources =
        [ 'https://email.a2p3.net/scope/default'
        , 'https://people.a2p3.net/scope/namePhoto'
var agentRequest = a2p3.agentRequest( config, vault, params )


Helper routine that generates 16 bytes of random data encoded as a URL safe base 64 string.

####Resource( config, vault )

Creates an A2P3 Resource object using the values in config and vault.

####Resource.exchange( agentRequest, ixToken, callback )

Exchanges an Agent Request and IX Token at the Identifier Exchange for the Apps directed identifier for the user and Resource Server Tokens for any requested resources.

  • agentRequest - the Agent Request sent to the Agent
  • ixToken - the IX Token received back from the Agent
  • callback( error, di ) - A callback which returns the Directed Identifier for the App, or an error

####Resource.call( api, [params], callback )

Calls the API with any parameters. Resource.exchange() MUST have been called previously. If the api is a to standaridized resource server, the host will be replaced with the first redirected resource server returned from the IX. To get results from all resource servers, use Resource.callMultiple()

  • api - the URL to the API
  • params - the parameters (if supplied) to be passed in the API. The required RS token parameter will be added automatically.
  • callback( error, results ) - A callback which returns the results from the API call, or an error

####Resource.callMultiple( details, callback )

Calls all supplied APIs in parrelel with the supplied parameters. Resource.exchange() MUST have been called previously. All resource servers provided by the Identifier Exchange for a standardize resource are called for any standardized resource API provided.

  • details - an object mapping resource APIs to params
  • callback( errors, results ) - A callback which returns an errors and results object.
    • errors - Any error returned from a host is added as a property to the errors object using the API. If there are no errors, then errors has the null value.
    • results - the results from each API call using the API as the property. If the API is a standardized resource, then a list of API redirects will be provided.

##Full Example

var a2p3 = require('a2p3')
  , config = require('./config.json')
  , vault = require('./vault.json')
  , params =
  { returnURL = 'http://localhost:8080'
  , resources =
    [ 'https://email.a2p3.net/scope/default'
    , 'https://people.a2p3.net/scope/namePhoto'
    , 'https://health.a2p3.net/scope/prov_number'
var agentRequest = a2p3.agentRequest( config, vault, params )
// send agentReqest to Agent, get back ixToken 
var rs new a2p3.Resources( config, vault )
  , details =
    { 'https://email.a2p3.net/email/default': null
    , 'https://people.a2p3.net/namePhoto': null
    , 'https://health.a2p3.net/prov_number': null
rs.exchange( agentRequest, ixToken, function ( errordi ) {
  if (!error) {
    console.log( di ) // { result: { sub: 'v1Gx5AsOf_91wjDQAwPsvrP' }} 
    rs.callMultiple( details, function ( errorsresults ) {
      if (!errors) {
        console.log( results )
// output of results: in this example, the user has health records at both BC and Alberta 
{ 'https://email.a2p3.net/email/default':
  { result : { email: 'john@example.com' } }
, 'https://people.a2p3.net/namePhoto':
  { redirect : [ 'https://people.bc.a2p3.net/namePhoto' ] }
, 'https://people.bc.a2p3.net/namePhoto':
  { result : { name: 'John Smith', photo: 'http://people.a2p3.net/photos/h5db2lkxHw7lks.jpeg' } }
, 'https://health.a2p3.net/prov_number':
  { redirect : [ 'https://health.ab.a2p3.net/prov_number', 'https://health.bc.a2p3.net/prov_number' ] }
, 'https://health.ab.a2p3.net/prov_number':
  { result : { prov_number: '1111111111' } }
, 'https://health.bc.a2p3.net/prov_number':
  { result : { prov_number: '2222222222' } }

A2P3 project home page

A2P3_specs Specifications and POC documentation

A2P3 POC Server implementation source (node.js)

A2P3_agent POC mobile agent (PhoneGap)

A2P3_bank POC mobile bank app (PhoneGap)

sample-node-a2p3 sample A2P3 application using node-a2p3