Skip to main content

14 posts tagged with "videos"

View All Tags

· One min read
Josh Twist

We recently shared some reasoning on why we think API keys are the best authentication approach for your public API.

We think this is so important that we built it as a feature of the Zuplo gateway. Our API Key management includes:

  • secure storage and management of keys and metadata - with an admin UI and API to manage consumers.
  • integrated developer portal with self-serve key management for your customers.

| Note, if you've already built your own API Key solution, and have a database store with your keys and users, we can easily integrate zuplo authentication with custom policies. It's never too late to make hosting your API much easier.

See it all in action in this 2-minute video:

Try it out now, for free at portal.zuplo.com

· 2 min read
Josh Twist

Have you noticed something the best API companies have in common?

Stripe, SendGrid, Twilio and Airtable logos

Folks like Stripe, Twilio, Airtable, SendGrid, and many more?

Yep, they all use API Keys as the primary authentication method for their APIs. Why is this?

There are two primary reasons

1/ Security

While there is no formal protocol for API Keys and most implementations have some level of variability - at least compared to standards like OAuth and OpenID Connect - they offer a good level of security, arguably greater than using JWT tokens for a few reasons.

  • Revokability - API Keys can be quickly revoked for any reason, whereas JWT tokens are hard to revoke and often require the reset of an entire certificate or tenant.
  • Opaqueness - unlike JWT tokens, which can be easily decoded using services like jwt.io, API keys are completely opaque and don’t reveal any hint of your internal authorization mechanism.
  • Self-management - a good API program with API keys allows consumers to manage API keys themselves and, in the event of a leak (or accidental push to a GitHub repo), the consumer can quickly revoke and roll their keys. If the same mishap occurs with a JWT token, it is typically harder for the consumer to self-serve and revoke the validity of the JWT token.

2/ Optimizing Time to First Call (TTFC)

Great API companies focus on developer experience and obsess about metrics like time-to-first-call. That is, how long does it take for a developer to find your documentation and get everything set up, and successfully invoke your API.

If you choose an authentication option that has some complexity (token acquisition, token refresh, etc) you are automatically increasing that Time to First Call and thus reducing the conversion rate of developers that get to know and adopt your platform.

Summary

Of course, there are valid reasons to use a more complex authentication method for your API, particularly if the consumer is doing work on behalf of another identity (e.g. accessing the GitHub API on behalf of a GitHub user) then OAuth makes the most sense.

However, if you’re primarily identifying the B2B business partners, API keys are a secure choice that is easy to use and will optimize the conversion funnel for winning new developers.

· 2 min read
Josh Twist

AKA Why you need rate-limiting, and ideally Dynamic Rate Limiting.

Length: 2 minutes

Before launching any API program you need to think about protection. Many API developers don't think they need to worry about rate-limiting because they aren't a target for hackers. That's probably true in the early days, but it isn't the hackers that are going to DoS you; it's your prized customers.

The most common type of API abuse isn't malicious, it's accidental. It's a misplaced for-loop in your partners code that takes you down. This happens often.

So ideally your API has some per-user rate limits. This is super easy with Zuplo.

However, in reality this isn't enough. You should probably have different rate-limits for different customers. For example, your free customers should have a more restrictive policy while your paid, or premium customers a more lenient one.

Guess what? That's also easy with Zuplo because you can write custom code that tells the rate-limit policy how to work. In the video above we show how you can modify the policy limits based on customer type (in this example, stored in the API Key metadata, but could be based on JWT claim, or even a cache-able DB lookup if so required).

Here's the code from request-limit-lookup.ts file in the video:

import { CustomRateLimitPolicyOptions, ZuploRequest } from "@zuplo/runtime";

const requestsPerMinute = {
premium: 3,
free: 1,
};

export default function (request: ZuploRequest): CustomRateLimitPolicyOptions {
const customerType = request.user.data.customerType;
const reqsPerMinute = requestsPerMinute[customerType];

const rateLimitConfig = {
// The key tells the rate limiter how to correlate different requests
key: request.user.sub,
requestsAllowed: reqsPerMinute,
timeWindowMinutes: 1,
};

return rateLimitConfig;
}

And the config for the rate-limit policy

{
"export": "BasicRateLimitInboundPolicy",
"module": "$import(@zuplo/runtime)",
"options": {
"rateLimitBy": "function",
"identifier": {
"module": "$import(./modules/request-limit-lookup)",
"export": "default"
}
}
}

Stay safe out there folks!

· One min read
Josh Twist

· One min read
Josh Twist

Length: 1 minute

Maybe my favorite video of the series. So if you use AWS Lambda you're probably using the AWS API Gateway. We're sorry to hear that. But fear not, there is an alternative. A real gateway with more features than you can shake at a fresh copy of Monkey Island that outperforms AWS API Gateway calling Lambda? It can't be... can it?

· One min read
Josh Twist

Length: 2 minutes

Zuplo is so fast and flexible, it is the easiest way to setup a mock API. Here we create a simple todo API (of course 🤦🏼‍♂️). We add our 'sleep' policy to make it slow too - so you can call this from your UI client and simulate long loading times.

Here's the code for the request handler:

import { ZuploContext, ZuploRequest } from "@zuplo/runtime";

export default async function (request: ZuploRequest, context: ZuploContext) {
return [
{ text: "Learn Javascript", done: false },
{ text: "Learn Typescript", done: false },
{ text: "Play around in Zuplo", done: true },
{ text: "Build something awesome", done: true },
];
}

Have fun, APIFiddling!

· One min read
Josh Twist

Length: 2 minutes

In this post we pickup where left off in this post Gateway over SaaS? and take our AirTable API and make it work directly with a form POST from a website.

It even has a honeypot field to filter out simple bots 👏

Here's the form post code from JSFiddle

<form method="POST" action="<YOUR ZUPLO API URL HERE>">
<input type="text" name="name" value="" />
<input type="text" name="email" value="" />
<input type="text" style="display:hidden" name="hp" value="" />
<button>submit</button>
</form>

· One min read
Josh Twist

Length: 2 minutes

This one's a little extra. Zuplo is so programmable you can use it in ways you've never considered for a gateway... a gateway over SaaS APIs - like AirTable.

In this example we use the Event Planning Template.

And here's the code in our request handler

import { ZuploContext, ZuploRequest } from "@zuplo/runtime";
import env from "@app/environment";

export default async function (request: ZuploRequest, context: ZuploContext) {
const body = await request.json();

const data = {
records: [
{
fields: {
Name: body.name,
Email: body.email,
},
},
],
};

const response = await fetch(env.ATTENDEES_URL, {
method: "POST",
headers: {
Authorization: `Bearer ${env.API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify(data),
});

if (!response.ok) {
return new Response("Error calling AirTable!", {
status: 500,
});
}
return new Response("Success", {
status: 200,
});
}

· 2 min read
Josh Twist

Length: 3 minutes

One of my favorite features of Zuplo is the ability to build custom policies. Here we create a custom policy to archive every request to Amazon's S3 storage. Here's the code in our archive-request.ts module:

import { ZuploContext, ZuploRequest } from "@zuplo/runtime";
import { S3Client, PutObjectCommand } from "@aws-sdk/client-s3";
import env from "@app/environment";

type MyPolicyOptionsType = {
myOption: any;
};
export default async function (
request: ZuploRequest,
context: ZuploContext,
options: MyPolicyOptionsType,
policyName: string
) {
context.log.info(env.AWS_SECRET_ACCESS_KEY);

const s3Client = new S3Client({ region: "us-east-2" });
const file = `${Date.now()}-${crypto.randomUUID()}.req.txt`;

const clone = request.clone();

const uploadParams = {
Bucket: "request-storage",
Key: file,
Body: await clone.text(),
};

const data = await s3Client.send(new PutObjectCommand(uploadParams));

return request;
}

Note, the code above will update S3 in serial with invoking your API, which will increase the latency of your API. However, you can also do this asynchronously, as follows:

import { ZuploContext, ZuploRequest } from "@zuplo/runtime";
import { S3Client, PutObjectCommand } from "@aws-sdk/client-s3";
import env from "@app/environment";

type MyPolicyOptionsType = {
myOption: any;
};
export default async function (
request: ZuploRequest,
context: ZuploContext,
options: MyPolicyOptionsType,
policyName: string
) {
context.log.info(env.AWS_SECRET_ACCESS_KEY);

const s3Client = new S3Client({ region: "us-east-2" });
const file = `${Date.now()}-${crypto.randomUUID()}.req.txt`;

const clone = request.clone();

const uploadParams = {
Bucket: "request-storage",
Key: file,
Body: await clone.text(),
};

const dataPromise = s3Client.send(new PutObjectCommand(uploadParams));
// This tells the runtime to not shutdown until that promise is complete
context.waitUntil(dataPromise);

return request;
}