Skip to content

Commit

Permalink
docs: api key creation and validation (#22)
Browse files Browse the repository at this point in the history
  • Loading branch information
chronark committed Jun 16, 2023
1 parent 02ead5d commit 837592d
Show file tree
Hide file tree
Showing 5 changed files with 316 additions and 7 deletions.
11 changes: 9 additions & 2 deletions apps/api/src/router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,24 +31,31 @@ export type Variables = {
export function init({ db, logger, ratelimiter, cache }: Bindings) {
const app = new Hono<{ Variables: Variables }>();
app.onError((err, c) => {
logger.error(err.message);
if (err instanceof HTTPException) {
return err.getResponse();
}

const log = c.get("logger") ?? logger;
log.error("unhandled error", { error: err.message, stack: err.stack });

return c.json({ error: "Internal Server Error", message: err.message }, { status: 500 });
});

// add request id
app.use("*", async (c, next) => {
const requestId = newId("request");

c.set("requestId", requestId);
c.res.headers.set("x-request-id", requestId);
await next();
});

// add request id
app.use("*", async (c, next) => {
c.set("logger", logger.with({ requestId: c.get("requestId"), path: c.req.path }));
const log = logger.with({ requestId: c.get("requestId"), path: c.req.path })
log.info("incoming request")
c.set("logger", log);

await next();
});

Expand Down
15 changes: 14 additions & 1 deletion apps/docs/api-reference/authentication.mdx
Original file line number Diff line number Diff line change
@@ -1,4 +1,17 @@
---
title: "Authentication"
description: "How to authenticate with Unkey.dev"
description: "Example overview page before API endpoints"
---

You'll need to authenticate your requests to access some of the endpoints in the Unkey API. In this guide, we'll look at how authentication works. {{ className: 'lead' }}

## Bearer Token

When requesting resources, you will need your access token — you will find it in the [Dashboard](#) in the settings when you click on your profile picture. Here's how to add the token to the request header using cURL:

```bash
curl https://api.unkey.app/v1/... \
-H "Authorization: Bearer unkey_xxx"
```

Always keep your token safe and reset it if you suspect it has been compromised.
208 changes: 208 additions & 0 deletions apps/docs/api-reference/keys/create.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,208 @@
---
title: "Create Key"
description: "Create an api key for your users"
api: "POST /v2/keys"
authMethod: "bearer"

---

## Request

<ParamField body="apiId" type="string" required>
Choose an `API` where this key should be created.

Read more about `API`'s here: TODO: james
</ParamField>


<ParamField body="prefix" type="string" >
To make it easier for your users to understand which product an api key belongs to, you can add prefix them.

For example Stripe famously prefixes their customer ids with `cus_` or their api keys with `sk_live_`.

The underscore is automtically added if you are defining a prefix, for example: `"prefix": "abc"` will result in a key like `abc_xxxxxxxxx`

</ParamField>


<ParamField body="byteLength" type="int" default={16} >
The bytelength used to generate your key determines its entropy as well as its length.
Higher is better, but keys become longer and more annoying to handle.

The default is `16 bytes`, or 2<sup>128</sup> possible combinations
</ParamField>


<ParamField body="ownerId" type="string" >
Your user's Id. This will provide a link between Unkey and your customer record.

When validating a key, we will return this back to you, so you can clearly identify your user from their api key.

</ParamField>

<ParamField body="meta" type="object" >
This is a place for dynamic meta data, anything that feels useful for you should go here

Example:
```json
{
"billingTier":"PRO",
"trialEnds": "2023-06-16T17:16:37.161Z"
}
```

</ParamField>
<ParamField body="expires" type="int" >
You can auto expire keys by providing a unix timestamp in milliseconds.

Once keys expire they will automatically be deleted and are no longer valid.


</ParamField>

<ParamField body="ratelimit" type="Object" >

Unkey comes with per-key ratelimiting out of the box.

<Expandable title="properties">

<ParamField body="type" type="string" default="fast" required>
Either `fast` or `consistent`.

TODO: andreas - explain

</ParamField>
<ParamField body="limit" type="int" required>
The total amount of burstable requests.


</ParamField>
<ParamField body="refillRate" type="int" required>
How many tokens to refill during each `refillInterval`
</ParamField>
<ParamField body="refillInterval" type="int" required>
Determines the speed at which tokens are refilled.

In milliseconds
</ParamField>
</Expandable>
</ParamField>

## Response

<ResponseField name="id" type="string" required>
The endpoint ID.
</ResponseField>
<ResponseField name="method" type="string" required>
The HTTP method to use when making requests to this endpoint.
</ResponseField>
<ResponseField name="name" type="string" required>
The name of the endpoint.
</ResponseField>
<ResponseField name="teamId" type="string" required>
The ID of the team that owns this endpoint.
</ResponseField>
<ResponseField name="url" type="string" required>
The URL of the endpoint.
</ResponseField>
<ResponseField name="createdAt" type="string" required>
When this endpoint was created.
</ResponseField>


<ResponseField name="updatedAt" type="string" required>
When this endpoint was last updated.
</ResponseField>
<ResponseField name="followRedirects" type="boolean" required>
Whether or not to follow redirects when making requests to this endpoint.
If `false`, redirects will be returned as responses.
</ResponseField>
<ResponseField name="prewarm" type="boolean" required>
Whether or not to prewarm this endpoint.
When `true`, the endpoint will be called twice and only the second response will be measured.
</ResponseField>
<ResponseField name="runs" type="number" required>
The number of runs to make when measuring this endpoint.
</ResponseField>
<ResponseField name="interval" type="number" required>
The interval between checks. In milliseconds.
</ResponseField>
<ResponseField name="active" type="boolean" required>
Whether or not this endpoint is active.
</ResponseField>
<ResponseField name="degradedAfter" type="number">
After this time in milliseconds, the endpoint will be considered degraded.
</ResponseField>
<ResponseField name="timeout" type="number" required>
The timeout for requests to this endpoint. In milliseconds.
</ResponseField>
<ResponseField name="distribution" type="ALL | RANDOM" required>
The distribution of runs across regions. `ALL` will run in all regions at the same time. `RANDOM` will run in a random region.
</ResponseField>

<ResponseField name="regions" type="Array" required>
<Expandable title="properties">

<ResponseField name="id" type="string" required>
The ID of the region.
</ResponseField>
</Expandable>
</ResponseField>


<ResponseField name="headers" type="Record<string, string>" >
The headers to send with requests to this endpoint.
</ResponseField>

<ResponseField name="body" type="string" >
The body to send with requests to this endpoint.
</ResponseField>

<ResponseField name="assertions" type="Array" >
Assertions to run against responses from this endpoint.
</ResponseField>


<RequestExample>



```sh
curl --request POST \
--url https://api.unkey.dev/v1/keys \
--header 'Authorization: Bearer <UNKEY>' \
--header 'Content-Type: application/json' \
--data '{
"apiId":"api_7oKUUscTZy22jmVf9THxDA",
"prefix":"xyz",
"byteLength":16,
"ownerId":"chronark",
"meta":{
"hello": "world"
},
"expires": 1686941966471,
"ratelimit":{
"type":"fast",
"limit":10,
"refillRate": 1,
"refillInterval": 1000
}
}'
```





</RequestExample>

<ResponseExample>
```json
{
"key": "xyz_AS5HDkXXPot2MMoPHD8jnL"
}
```


</ResponseExample>
71 changes: 71 additions & 0 deletions apps/docs/api-reference/keys/verify.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
---
title: "Verify Key"
description: "Verify a key"
api: "POST /v2/keys/verify"

---

Verify a key from your users. Notice how this endpoint does not require an Unkey api key. You only need to send the api key from your user.

## Request

<ParamField body="key" type="string" required>
The key you want to verify.
</ParamField>

## Response

<ResponseField name="valid" type="boolean" required>
Whether or not this key is valid and has passed the ratelimit.
If `false` you should not grant access to whatever the user is requesting
</ResponseField>
<ResponseField name="ownerId" type="string">
If you have set an `ownerId` on this key it is returned here. You can use this to clearly authenticate a user in your system.
</ResponseField>


<ResponseField name="meta" type="object" >
This is the `meta` data you have set when creating the key.

Example:
```json
{
"billingTier":"PRO",
"trialEnds": "2023-06-16T17:16:37.161Z"
}
```

</ResponseField>

<RequestExample>



```sh
curl --request POST \
--url https://api.unkey.dev/v1/keys/verify \
--header 'Content-Type: application/json' \
--data '{
"key":"xyz_AS5HDkXXPot2MMoPHD8jnL"
}'
```





</RequestExample>

<ResponseExample>
```json
{
"valid": true,
"ownerId": "chronark",
"meta": {
"hello": "world"
}
}
```


</ResponseExample>
18 changes: 14 additions & 4 deletions apps/docs/mint.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@
"$schema": "https://mintlify.com/schema.json",
"name": "Unkey Docs",
"colors": {
"primary": "#252737",
"primary": "#6030B3",
"light": "#c2c4c4",
"dark": "#252737"
},
"topbarLinks": [
{
"name": "Documentation",
"url": "https://docs.unkey.dev"
"name": "GitHub",
"url": "https://github.com/chronark/unkey"
}
],
"topbarCtaButton": {
Expand All @@ -34,7 +34,17 @@
{
"group": "API Documentation",
"pages": [
"api-reference/authentication"
"api-reference/authentication",

{
"group":"Keys",
"pages":[
"api-reference/keys/create",
"api-reference/keys/verify"


]
}
]
}
],
Expand Down

0 comments on commit 837592d

Please sign in to comment.