BlockchainProgrammer
BlockchainProgrammer

Reputation: 2069

Hyperledger Fabric Composer-Rest-Server how to setup a Username / Password Authentication?

First of all, I am very new to hyperledger and probably I am thinking wrong at some place.

Right now, I am working on an application that I am doing with Hyperledger Fabric, Hyperledger Composer and hyperledger-rest-server.

Now I read a bit about the authentication process but I got stuck at one point.

Before I get to my questions, I tell you a bit more about what I want:

I want to create a frontend application with angular where the user can log in with his username/password.

What I read is that I can use Passport.js for hyperledger-rest-server authentication. But what I understood, is that this is for authentication with third parties like twitter, facebook etc.

My Questions:

Upvotes: 0

Views: 335

Answers (1)

Varun Agarwal
Varun Agarwal

Reputation: 1587

Yes this is one such option and completely feasible. You can use passportjs with composer-rest-server and link a username to a unique composer business card. This way when the user logs in, it gets a token from the server. Every subsequent API call must have the token, based on this the rest server will use the required composer card

You would first need to follow this and setup your server using composer-rest-server -c ADMIN_CARD_NAME. You will then need to activate authentication for the server. Go to http://0.0.0.0:3000/explorer to view the APIs including those for authentication.

Based on the authentication method you would need to install the required package. This tutorial is a great place to start. Using the wallet import endpoint, the admin can map a Facebook account or a username to a particular composer card.

Now my honest opinion is, composer-rest-server is not suitable for a pilot/ production rollout. I have used this and ultimately decided to handle my own APIs and authentication.

  1. Create a participant and import the identity
async function createParticipant() {
    const businessNetworkConnection = new BusinessNetworkConnection();
    await businessNetworkConnection.connect(adminCardName);
    let registry=  await businessNetworkConnection.getParticipantRegistry(`${BASE_NS}.SampleUser`);
    const factory = businessNetworkConnection.getBusinessNetwork().getFactory();
    let user= factory.newResource(BASE_NS, 'SampleUser', 'username123');
    await businessNetworkConnection.save(user);
    // User is registered, time to import an identity
    let creds = await businessNetworkConnection.issueIdentity(`${BASE_NS}.SampleUser#username123`, 'username123);
    const adminConnection = new AdminConnection();
    await adminConnection.connect(adminCardName);
    const card = new IdCard({
        userName: creds.userID,
        version: 1,
        enrollmentSecret: creds.userSecret,
        businessNetwork: businessName
      }, connectionProfile);
    await adminConnection.importCard(`username123@my-network`, card);
    await adminConnection.disconnect();
    await businessNetworkConnection.disconnect();
}
  1. Use your own DB to store a username and password for a user. Map it to the composer card. For this example I have used mongoDB. The schema would be something like this
let newUser = new userSchema({
      username: 'Alice,
      password: 'topSecretPassword,
      emailId: '[email protected]',
      participantId: 'username123,
      composerCard: `username123@my-network`
});
  1. The middleware (most important). So when Alice logs in, the system will return a jsonwebtoken that she must use in all subsequent API calls.
const jwt = require('jsonwebtoken');

app.post('/login', auth());
async function auth(req, res, next) {
    let username = req.body.username;
    let password = req.body.password;
    // User whatever authentication method you want here and return a jwt
    // In my project I created a new token db and kept a mapping
    const authToken = jwt.sign(tokenSeed, jwtSecret, { });
    const newToken = new tokenSchema({
      authToken: authToken,
      username: req.body.username
    });
    await newToken.save();
    res.send({ authToken: authToken, username: username });
}
  1. The actual API call. So this is basically a middleware function that checks the token and decides which composer card to use for the transactions
const chooseCard = async (req, res, next) => {
    // Retrieve the token from the DB
    let token = await tokenSchema.findOne({ authToken: req.headers['x-access-token'] });
    // Get the user information
    let user = await userSchema.findOne({ username: token.username });
    let card = user.composerCard;
    req.composerCardToUse = card;
    next();
};

const someFancyTx = async (req, res, next) => {
    let card = req.composerCardToUse;
    await businessNetworkConnection.connect(card);
    // And the transactions submitted with this instance will use the required card


}

app.post('/sendMoney', chooseCard, somefancyTx);

NOTE: I have skipped a few validation steps (check authenticity of jwt, user session) and skipped some of the boilerplate code that would make this answer unnecessarily long. I have run a pilot and a PoC successfully using this same system.

Upvotes: 1

Related Questions