A node.js API proxy that keeps your API keys out of client side code.
- MongoDB
yarn
cp .env.sample .env
npm start
The proxy will be available at:
http://localhost:4444/api/v1
This POST request should NOT be made from the client side. Use curl
, Postman
etc.
POST /api/v1/client
- host - the host of the API to be proxied
- origins - array of allowed origins
- query - any custom query parameters to add to the request
- headers - any custom headers to add to the request
{
"host": "api.to.be.proxied.com",
"origins": [
"http://localhost:8080",
"https://only-allow-my-site.com"
],
"query": {
"key": "SUPER_SECRET_KEY_HERE"
},
"headers": {
"Authorization": "Bearer SUPER_SECRET_KEY_HERE"
}
}
SAVE this response somewhere! The client cannot be deleted/updated without the generated client_secret
.
The client_id
is what will be used in your client side app.
{
"client_id": "123456",
"client_secret": "789012",
"origins": [
"http://localhost:8080",
"https://only-allow-my-site.com"
],
"host": "api.to.be.proxied.com",
"query": {
"key": "SUPER_SECRET_KEY_HERE"
},
"headers": {
"Authorization": "Bearer SUPER_SECRET_KEY_HERE"
},
"_id": "987612345"
}
- The keyper.js client is an AJAX agnostic XMLHttpRequest interceptor.
- After configuration, any request that matches a specified host will be sent through the Keyper proxy.
Add the keyper.js client to your page:
<script src="keyper.js" charset="utf-8"></script>
Create an instance of the client, with your host and client_id specified:
var keyper = new Keyper({
host: 'http://localhost:4444/api/v1', // (default value) This is the URL of the Keyper proxy
debug: true, // (Defaults to false) Show logs and error messages. Turn OFF in production.
hosts: {
'api.to.be.proxied.com': {
client_id: '123456'
}
}
});
Initialize the client (before any AJAX calls):
keyper.initialize();
Initializing the client does 2 things:
- Generates an "instance" token
- A token that is unique to this client (browser)
- Creates an XMLHttpRequest interceptor that will proxy any request that match the hosts specified when you created the instance.
// Will be proxied
$.get('https://api.to.be.proxied.com/some/path?this=that')
.then(function(data) {
console.log(data);
}).catch(function(error) {
console.log(error);
});
// Will NOT be proxied:
$.get('https://not.in.the.config.com/some/other/path?this=that')
.then(function(data) {
console.log(data);
}).catch(function(error) {
console.log(error);
});
A unique instance is created when the Keyper client is initialized. The instance token is stored in localStorage. Request count for each instance is logged to the DB.
POST /api/v1/client/:id
- client_secret - the secret generated when the client was first created
POST /api/v1/client/123456
{
"client_secret": "789012"
}
[
{
"_id": "7890",
"client_id": "123456",
"request_count": 100,
"active": true
},
{
"_id": "3847",
"client_id": "123456",
"request_count": 999,
"active": true
}
]
If an instance is abusing your API Key, you may want to revoke access.
DELETE /api/v1/client/:id/instance/:instance_id
- client_secret - the secret generated when the client was first created
DELETE /api/v1/client/123456/instance/3847
{
"client_secret": "789012"
}
{
"message": "Instance deleted."
}
After being deleted, any future requests with the given instance token will be denied:
{
"error": "Keyper Error: No active instances found."
}
To re-activate a client instance, you'll need to invalidate the token and re-initialize:
keyper.invalidateToken(); // Refresh the page after invalidating
If an IP address is abusing your API Key, you may want to ban the IP outright.
POST /api/v1/client/:id/ban
- ips - Array of IPs to ban
POST /api/v1/client/123456/ban
{
"client_secret": "789012",
"ips": ["127.0.0.1"]
}
{
"message": "IP(s) banned"
}
After being banned, any future requests for an instance token will be denied:
{
"error": "Keyper Error: ⛔️"
}
This DELETE request should NOT be made from the client side. Use curl
, Postman
etc.
DELETE /api/v1/client/:id
- client_secret - the secret generated when the client was first created
DELETE /api/v1/client/123456
{
"client_secret": "789012"
}
{
"message": "client deleted"
}
After a client has been deleted, all attempts to make requests using the deleted client_id will fail.