Skip to content

DSorlov/jsFreja

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

23 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation


Project license Pull Requests welcome code with love by dsorlov

freja

About

This project is created as a simple way of interacting with the Freja REST API from Node.js. The problem is not that the REST API is hard to use in it self but rather to make a friendlier way to inteact interact and integrate. The freja module commes with typings, jsdoc typings, and practical shortcut functions to common functions and actions. You do not have to encode or decode, veryify and keep track of what URIs are used for what. The module does that for you. Kind of like magic.

This module can interact with most parts of Freja.

  • Authentication Service
  • Signature Service
  • Organisation ID Service
  • Custom Identifiers
  • Custodianship Service

The module is created after many years as a part of my eid moddule, and as many parts of that module were less and less used and the code getting old I decided to branch of into this for just the Freja parts and also raise the bar with more documentation and typings etc. In due time eid will probably be archived.

Getting Started

The module is built as an ES6/CommonJS module. The only external dependency except node itself is jsonwebtoken. It should be usable on many different enviroments such as Bun but we do not test for that for now.

Prerequisites

TL;DR There really is no must-do to get started in the testing enviroment.

To get started you can obtain your own testing certifiate from Freja but we have also by special arrangement with Freja included one for you already which you may use for testing (it will not work in production). Before going to production you will need a production certificate from Freja to start up your services, which you will get after signing a contract.

Installation

npm install freja

Documentation

This page should give you most hints and the knowledge needed to use the module. There is also some documentation to help you get insights to the objects and more.

Introduction

The basic and most used function is initRequest() method however there is some shortcut methods defined such as initAuth(), initSign(), initSignBuffer() and initAddOrganisationId() which all have some good default values set so you dont need to send the arguments to initRequest().

This is a breif example of an authentication request. The following code is initializing the library with a specified pfx and password. Relative paths are ok. Then we set the minimum requested level using FrejaAPI.FrejaRegistrationLevel for the authentication and which attributes to return. Either the FrejaAPI.FrejaUserAttributeCollections or the FrejaAPI.FrejaUserAttributes can be used to assist in getting the right value.

import { FrejaAPIEnvironment, FrejaAPI, FrejaRegistrationLevel, FrejaUserAttributeCollections } from 'freja';

const frejaApi = new FrejaAPI(FrejaAPIEnvironment.TEST,'<path-to-your-pfx>','<pfx-password>');
frejaApi.RegistrationLevel = FrejaRegistrationLevel.PLUS;
frejaApi.UserAttributes = FrejaUserAttributeCollections.ALL_EXTENDED;

Next let us execute the request. The following code with get us a code to use with a QR-reader or in a mobile app. You can also supply arguments to the initAuthRequest to make sure a specific user is targeted.

let result = await frejaApi.InitAuthRequest();

All operations we execute returns objects of the IResultMessage or one of its derrative classes. They all have a isOk property (boolean). isOk means the operation was successfull.

Next we define a function to check status in the test script. This function will be called every 2.5s as suggested by Freja. We check the response and if its property isFinal (boolean) is true: we have got a final result. Otherwise we just continue pulling here. Also a good expansion of this code could be to also handle fault stats where the isOk flag is false.

let checkResult = await frejaApi.InquireRequest(result.token)

Errors will have the isOk set to false and code field set to something you can lookup in FrejaAPI.GetErrorCode() if you need a verbose message.

When an authentication request finishes you will get a ICompletedRequestMessage where the data property will be a IFrejaUserInfo where you will find your requested attributes for the user.

Autentication Example

So putting the above together into an simple example for an authentication client. This will initiate an authentication request, and poll untill we got a result.

// @ts-check
import { FrejaAPIEnvironment, FrejaAPI, FrejaRegistrationLevel, FrejaUserAttributeCollections } from 'freja';

//Setup some API testing stuff
const frejaApi = new FrejaAPI(FrejaAPIEnvironment.PRODUCTION,'<path-to-pfxfile>','<pfxfile-password>');
frejaApi.RegistrationLevel = FrejaRegistrationLevel.PLUS;
frejaApi.UserAttributes = FrejaUserAttributeCollections.ALL_EXTENDED;

// Initiate an authentication request
var result = await frejaApi.AuthRequest('<identifier>');

// Check if the request was successful
if (result.isOk) {
    console.log(`Token: ${result.token}`);
} else {
    console.error(result);
    process.exit(1);
}

async function checkStatus() {

    //Get current status of the request
    var checkResult = await frejaApi.InquireRequest(result.token);
    
    //The status is not final yet?
    if (checkResult.isOk && !checkResult.isFinal) {
        setTimeout(checkStatus, 2500);
        console.log('Not final yet: ' + checkResult.status);
    } else {
        console.log('Final status: ' + checkResult.status);
        console.log(checkResult);
    }
}

//Check status every 2.5 seconds
setTimeout(checkStatus, 2500);

Signing Example 1 (Simple)

The only difference when doing a sign request is basically that you also need to send text and title of the signing. The initSign expects a identifier (because normally you would like to have a specific person sign and not just the first to scan), it could be set to nothing if needed.

var result = await frejaApi.InitSignRequest('<identifier>','title to sign','text to sign');

Signing Example 2 (Buffer and OrgId)

You can also send a hidden piece of information with as proof of the signing. This is done via a Buffer containing the data you need signed. Also in this example we are using the OrgId service (last argument), if you dont need that just remove that parameter.

var result = await frejaApi.InitSignBufferRequest('<identifier>','title to sign','text to sign', <data-in-a-buffer>, true);

Adding OrgId

To issue an OrgId you must send a request for the person to accept the id. To start such a process you can use the

var result = await frejaApi.AddOrgIdRequest('<identifier>','<org-name>','<attribute-name>','<attribute-value>');

All methods

The fundamental methods are

frejaApi.InitRequest(<requestType:RequestType>, <userInfo:IUserInfo|string|undefined>, <additionalParams:Object>);
frejaApi.CancelRequest(<token:string>);
frejaApi.InquireRequest(<token:string>);

Shortcut methods to make life easier are most commonly used.

frejaApi.AuthRequest(<userInfo:IUserInfo|string|undefined>)
frejaApi.SignRequest(<userInfo:IUserInfo|string|undefined>,<title:string>,<text:string>);
frejaApi.SignBufferRequest(<userInfo:IUserInfo|string|undefined>,<title:string>,<text:string>, <data:Buffer>);
frejaApi.AddOrgIdRequest(<userInfo:IUserInfo|string>,<org-name:string>,<attribute-name:string>,<attribute-value:string>);

OrgId Specific

frejaApi.UpdateOrgId(<identifier:string>,<additionalAttributeList[]>);
frejaApi.RevokeOrgId(<identifier:string>);

Not so commonly used functions

frejaApi.CheckCustodianship(<swedishSSN:string>);
frejaApi.NewCustomIdentifier(<customIdentifier:string>,<userInfo:IUserInfo|string>);
frejaApi.DeleteCustomIdentifier(<customIdentifier:string>);

additionalParams

The additionalParams object is used when doing advanced Requests directly via InitRequest() Depending on the type of requests theese can be combined in different ways and a good amount of local validation is done before trying the request.

The most common are (for all types of requests)

For requests of signing (both standard and orgid signing)

  • waitDays {Number} how long the transaction should live. 1-30 days (default is 1 day)
  • text {String} The message presented when signing
  • signatureType {FrejaSignatureType} for the signature you wish in the response
  • binaryData {Buffer} a buffer with any data to include in the signature
  • notification {IFrejaSignNotification} describing the user device notification

For adding a orgId (only when adding a new orgid)

Roadmap

See the open issues for a list of proposed features (and known issues).

Support

Reach out to the maintainer at one of the following places:

Project assistance

If you want to say thank you or/and support active development of freja:

  • Add a GitHub Star to the project.
  • Tweet about freja.
  • Write interesting articles about the project on Dev.to, Medium or your personal blog.

Together, we can make freja better!

Contributing

First off, thanks for taking the time to contribute! Contributions are what make the open-source community such an amazing place to learn, inspire, and create. Any contributions you make will benefit everybody else and are greatly appreciated.

Please read our contribution guidelines, and thank you for being involved!

Authors & contributors

The original setup of this repository is by Daniel Sörlöv.

For a full list of all authors and contributors, see the contributors page.

Security

jsfreja follows good practices of security, but 100% security cannot be assured. jsfreja is provided "as is" without any warranty. Use at your own risk.

For more information and to report security issues, please refer to our security documentation.

License

This project is licensed under the MIT license.

See LICENSE for more information.

Acknowledgements

Huge thanks to Freja eID Group and specifically @vetobus for providing me with access to senior technical staff and accepting my suggestions for improvements and beeing so open to the developer community in general.

Also thanks to auth0 for the excellently stable jsonwebtoken module used to authenticate the data.