Update api key header

Use more common X-Api-Key header with no prefix

Also updates Unauthorized response to include a json error body
and simplifies working with new API key via curl and the vscode
rest client

Signed-off-by: James Taylor <jamest@uk.ibm.com>
This commit is contained in:
James Taylor 2021-07-27 15:35:40 +01:00
parent c3a34ef559
commit 05f7026e58
5 changed files with 145 additions and 98 deletions

View file

@ -48,52 +48,60 @@ npm run start:dev
## REST API
If everything went well, you can now make basic asset transfer REST calls! For example...
If everything went well, you can now make basic asset transfer REST calls!
The examples below require a `SAMPLE_APIKEY` environment variable which must be set to an API key from the `.env` file created above.
For example, to use the ORG1_APIKEY...
```
SAMPLE_APIKEY=$(grep ORG1_APIKEY .env | cut -d '=' -f 2-)
```
### Get all assets...
```shell
curl http://localhost:3000/api/assets
curl --header "X-Api-Key: ${SAMPLE_APIKEY}" http://localhost:3000/api/assets
```
### Check whether an asset exists...
```shell
curl --include --request OPTIONS http://localhost:3000/api/assets/asset7
curl --include --header "X-Api-Key: ${SAMPLE_APIKEY}" --request OPTIONS http://localhost:3000/api/assets/asset7
```
### Create an asset...
```shell
curl --include --header "Content-Type: application/json" --header "api-key:Api-Key <apikeyfororg>" --request POST --data '{"id":"asset7","color":"red","size":42,"owner":"Jean","appraisedValue":101}' http://localhost:3000/api/assets
curl --include --header "Content-Type: application/json" --header "X-Api-Key: ${SAMPLE_APIKEY}" --request POST --data '{"id":"asset7","color":"red","size":42,"owner":"Jean","appraisedValue":101}' http://localhost:3000/api/assets
```
### Read transaction status...
```shell
curl --header "api-key:Api-Key <apikeyfororg>" http://localhost:3000/api/transactions/__transaction_id__
curl --header "X-Api-Key: ${SAMPLE_APIKEY}" http://localhost:3000/api/transactions/__transaction_id__
```
### Read an asset...
```shell
curl --header "api-key:Api-Key <apikeyfororg>" http://localhost:3000/api/assets/asset7
curl --header "X-Api-Key: ${SAMPLE_APIKEY}" http://localhost:3000/api/assets/asset7
```
### Update an asset...
```shell
curl --include --header "Content-Type: application/json" --header "api-key:Api-Key <apikeyfororg>" --request PUT --data '{"id":"asset7","color":"red","size":11,"owner":"Jean","appraisedValue":101}' http://localhost:3000/api/assets/asset7
curl --include --header "Content-Type: application/json" --header "X-Api-Key: ${SAMPLE_APIKEY}" --request PUT --data '{"id":"asset7","color":"red","size":11,"owner":"Jean","appraisedValue":101}' http://localhost:3000/api/assets/asset7
```
### Transfer an asset...
```shell
curl --include --header "Content-Type: application/json" --header "api-key:Api-Key <apikeyfororg>" --request PATCH --data '[{"op":"replace","path":"/owner","value":"Ashleigh"}]' http://localhost:3000/api/assets/asset7
curl --include --header "Content-Type: application/json" --header "X-Api-Key: ${SAMPLE_APIKEY}" --request PATCH --data '[{"op":"replace","path":"/owner","value":"Ashleigh"}]' http://localhost:3000/api/assets/asset7
```
### Delete an asset...
```shell
curl --include --header "api-key:Api-Key <apikeyfororg>" --request DELETE http://localhost:3000/api/assets/asset7
curl --include --header "X-Api-Key: ${SAMPLE_APIKEY}" --request DELETE http://localhost:3000/api/assets/asset7
```

View file

@ -0,0 +1,84 @@
// Demo file for use with REST Client for Visual Studio Code
// See https://github.com/Huachao/vscode-restclient
//
// Edit the values below to match your environment if required
@hostname = localhost
@port = {{$dotenv PORT}}
@baseUrl = http://{{hostname}}:{{port}}
@apiUrl = {{baseUrl}}/api
@api-key = {{$dotenv ORG1_APIKEY}}
### Check the server is ready
GET {{baseUrl}}/ready HTTP/1.1
### Check the server is still live
GET {{baseUrl}}/live HTTP/1.1
### Get all assets
GET {{apiUrl}}/assets HTTP/1.1
X-Api-Key: {{api-key}}
### Check if asset exists
OPTIONS {{apiUrl}}/assets/asset7 HTTP/1.1
X-Api-Key: {{api-key}}
### Create asset
POST {{apiUrl}}/assets HTTP/1.1
content-type: application/json
X-Api-Key: {{api-key}}
{
"id": "asset7",
"color": "red",
"size": 42,
"owner": "Jean",
"appraisedValue": 101
}
### Read transaction status
GET {{apiUrl}}/transactions/__transaction_id__ HTTP/1.1
X-Api-Key: {{api-key}}
### Read asset
GET {{apiUrl}}/assets/asset7 HTTP/1.1
X-Api-Key: {{api-key}}
### Update asset
PUT {{apiUrl}}/assets/asset7 HTTP/1.1
content-type: application/json
X-Api-Key: {{api-key}}
{
"id": "asset7",
"color": "red",
"size": 11,
"owner": "Jean",
"appraisedValue": 101
}
### Transfer asset
PATCH {{apiUrl}}/assets/asset7 HTTP/1.1
content-type: application/json
X-Api-Key: {{api-key}}
[
{
"op": "replace",
"path": "/owner",
"value": "Ashleigh"
}
]
### Delete asset
DELETE {{apiUrl}}/assets/asset7 HTTP/1.1
X-Api-Key: {{api-key}}

View file

@ -1,24 +1,61 @@
/*
* SPDX-License-Identifier: Apache-2.0
*/
import { logger } from './logger';
import passport from 'passport';
import { NextFunction, Request, Response } from 'express';
import { HeaderAPIKeyStrategy } from 'passport-headerapikey';
import { StatusCodes, getReasonPhrase } from 'http-status-codes';
import * as config from './config';
const { UNAUTHORIZED } = StatusCodes;
export const fabricAPIKeyStrategy: HeaderAPIKeyStrategy =
new HeaderAPIKeyStrategy(
{ header: 'api-key', prefix: 'Api-Key ' },
true,
{ header: 'X-API-Key', prefix: '' },
false,
function (apikey, done) {
logger.debug({ apikey }, 'Checking X-API-Key');
const user: { org: string } = {
org: '',
};
if (apikey === config.org1ApiKey) {
user.org = 'Org1';
logger.info('Organisation set to Org1');
logger.debug('Organisation set to Org1');
done(null, user);
//todo
//add org2 apikey check
} else {
logger.debug('APIKEY Mismatch');
logger.debug({ apikey }, 'No valid X-API-Key');
return done(null, false);
}
}
);
export const authenticateApiKey = (
req: Request,
res: Response,
next: NextFunction
): void => {
passport.authenticate(
'headerapikey',
{ session: false },
function (err, user, _info) {
if (err) return next(err);
if (!user)
return res.status(UNAUTHORIZED).json({
status: getReasonPhrase(UNAUTHORIZED),
reason: 'NO_VALID_APIKEY',
timestamp: new Date().toISOString(),
});
req.logIn(user, { session: false }, (err) => {
if (err) {
return next(err);
}
return next();
});
}
)(req, res, next);
};

View file

@ -22,7 +22,7 @@ const {
SERVICE_UNAVAILABLE,
} = StatusCodes;
import { fabricAPIKeyStrategy } from './auth';
import { authenticateApiKey, fabricAPIKeyStrategy } from './auth';
import passport from 'passport';
export const createServer = async (): Promise<Application> => {
const app = express();
@ -98,16 +98,8 @@ export const createServer = async (): Promise<Application> => {
throw new Error('Example error');
});
app.use(
'/api/assets',
passport.authenticate('headerapikey', { session: false }),
assetsRouter
);
app.use(
'/api/transactions',
passport.authenticate('headerapikey', { session: false }),
transactionsRouter
);
app.use('/api/assets', authenticateApiKey, assetsRouter);
app.use('/api/transactions', authenticateApiKey, transactionsRouter);
// For everything else
app.use((_req, res) =>

View file

@ -1,74 +0,0 @@
// Demo file for use with REST Client for Visual Studio Code
// See https://github.com/Huachao/vscode-restclient
@hostname = localhost
@port = 3000
@baseUrl = http://{{hostname}}:{{port}}/api
//Get the apikey from .env file
@api-key= Api-Key 295069C9-ABF5-4D2A-A020-2FF9F4E8DF07
### Get all assets
GET {{baseUrl}}/assets HTTP/1.1
api-key: {{api-key}}
### Check if asset exists
OPTIONS {{baseUrl}}/assets/asset7 HTTP/1.1
api-key: {{api-key}}
### Create asset
POST {{baseUrl}}/assets HTTP/1.1
content-type: application/json
api-key: {{api-key}}
{
"id": "asset7",
"color": "red",
"size": 42,
"owner": "Jean",
"appraisedValue": 101
}
### Read transaction status
GET {{baseUrl}}/transactions/__transaction_id__ HTTP/1.1
api-key: {{api-key}}
### Read asset
GET {{baseUrl}}/assets/asset7 HTTP/1.1
api-key: {{api-key}}
### Update asset
PUT {{baseUrl}}/assets/asset7 HTTP/1.1
content-type: application/json
api-key: {{api-key}}
{
"id": "asset7",
"color": "red",
"size": 11,
"owner": "Jean",
"appraisedValue": 101
}
### Transfer asset
PATCH {{baseUrl}}/assets/asset7 HTTP/1.1
content-type: application/json
api-key: {{api-key}}
[
{
"op": "replace",
"path": "/owner",
"value": "Ashleigh"
}
]
### Delete asset
DELETE {{baseUrl}}/assets/asset7 HTTP/1.1
api-key: {{api-key}}