Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
INTEGRATION_PUBLIC_KEY=
BASE_API_PATH=
24 changes: 24 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*

# Dependency directories
node_modules/

# Optional npm cache directory
.npm

# Yarn Integrity file
.yarn-integrity

# misc
package-lock.json
.DS_Store
.env
.serverless

# local dev debugging
.debug
1 change: 1 addition & 0 deletions .nvmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
18.20
24 changes: 0 additions & 24 deletions LICENSE

This file was deleted.

54 changes: 53 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,53 @@
# secure-api-proxy
# Secure API Proxy

This repository is a sample repo for wrapping the agnoStack API with secure encryption.

---

## Install

```bash
nvm use
yarn install
```

## Setup env vars

Create a `.env` from the provided example.

```bash
cp .env.example .env
```

Enter values for `INTEGRATION_PUBLIC_KEY` and `BASE_API_PATH` given the values provided from agnoStack.

## Local testing

```bash
yarn watch
```

Post requests can then be made via `http://localhost:3000/dev/agnoStack/orders/12345`

## Deployment

```bash
yarn deploy
```

## Making requests

All requests must contain the following request headers, provided from agnoStack.

- x-organization-id
- x-providerstack-id
- x-client-id
- x-client-secret

```bash
curl --location --request POST 'http://localhost:3000/dev/agnoStack/orders/12345' \
--header 'x-organization-id: YOUR_ORGANIZATION_ID' \
--header 'x-client-id: YOUR_CLIENT_ID' \
--header 'x-client-secret: YOUR_CLIENT_SECRET' \
--header 'x-providerstack-id: YOUR_PROVIDERSTACK_ID'
```
54 changes: 54 additions & 0 deletions handlers.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
const {
getVerificationKeysData,
prepareVerificationRequest,
processVerificationResponse,
} = require('@agnostack/verifyd')

const { BASE_API_PATH, INTEGRATION_PUBLIC_KEY } = process.env

const BASE_HEADERS = {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Credentials': true,
}

const proxy = async (event) => {
let statusCode
let body

try {
const keysData = await getVerificationKeysData(INTEGRATION_PUBLIC_KEY)
const _prepareVerificationRequest = prepareVerificationRequest({ keysData })
const _processVerificationResponse = processVerificationResponse({ keysData })

const url = `${BASE_API_PATH}/${event?.pathParameters?.route}`
const options = {
method: 'POST',
body: event?.body,
headers: event?.headers,
}

const [
requestPath,
requestOptions,
derivedSecretKey
] = await _prepareVerificationRequest(url, options) ?? []

const encryptedResponse = await fetch(requestPath, requestOptions).then((_response) => (
_response.json()
))

statusCode = 200
body = await _processVerificationResponse(encryptedResponse, derivedSecretKey)
} catch (error) {
const message = 'Error proxying API request'
console.error(message, error)

statusCode = 500
body = { error: message }
}

return { statusCode, body: JSON.stringify(body), headers: BASE_HEADERS }
}

module.exports = { proxy }
26 changes: 26 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{
"private": true,
"name": "@agnostack/secure-api-proxy",
"version": "1.0.0",
"author": "agnoStack Dev <developers@agnostack.com> (https://agnostack.com)",
"owner": "agnoStack",
"description": "Please contact agnoStack via info@agnostack.com for any questions",
"license": "UNLICENSED",
"homepage": "https://github.com/agnostack/secure-api-proxy/tree/develop#readme",
"repository": "github:agnostack/secure-api-proxy",
"engines": {
"node": ">=18.x"
},
"scripts": {
"deploy": "yarn serverless deploy",
"watch": "yarn serverless offline"
},
"dependencies": {
"@agnostack/verifyd": "latest"
},
"devDependencies": {
"serverless": "3.x",
"serverless-dotenv-plugin": "6.0.0",
"serverless-offline": "12.x"
}
}
44 changes: 44 additions & 0 deletions serverless.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
service: secure-api-proxy
frameworkVersion: "3"

plugins:
- serverless-dotenv-plugin
- serverless-offline

custom:
serverless-offline:
reloadHandler: true

provider:
name: aws
runtime: nodejs18.x
region: us-east-1

functions:
proxy:
handler: handlers.proxy
events:
- http:
path: /agnoStack/{route+}
method: post

resources:
Resources:
GatewayResponseDefault4XX:
Type: 'AWS::ApiGateway::GatewayResponse'
Properties:
ResponseParameters:
gatewayresponse.header.Access-Control-Allow-Origin: "'*'"
gatewayresponse.header.Access-Control-Allow-Headers: "'*'"
ResponseType: DEFAULT_4XX
RestApiId:
Ref: 'ApiGatewayRestApi'
GatewayResponseDefault5XX:
Type: 'AWS::ApiGateway::GatewayResponse'
Properties:
ResponseParameters:
gatewayresponse.header.Access-Control-Allow-Origin: "'*'"
gatewayresponse.header.Access-Control-Allow-Headers: "'*'"
ResponseType: DEFAULT_5XX
RestApiId:
Ref: 'ApiGatewayRestApi'
Loading