Skip to main content

Manage API keys

note

Speakeasy managed API keys is still in preview. Please reach out to us on Slack or at info@speakeasyapi.dev if you are interested in using this feature in production.

With Speakeasy you can enable your API users to manage long lived API keys that they can create and revoke themselves. Speakeasy Platform does not act as an authentication provider but instead integrates directly with your API gateway to externalise the management of API keys. For every API key managed by your gateway we will ensure one public/private RSA key pair is managed through Speakeasy. This enables a secure and scalable key management while leveraging the existing authentication and request termination mechanisms of your API gateway. For more info on how this works please see our reference on api key management.

We can currently integrate with any API Gateways that support OIDC workflows and external token sources. This includes Google Endpoints, Kong, Apigee, or a native Envoy solution. We've tested API key management at scale and can support hundreds of thousands of API keys without significant performance impact. Please reach out to us at info@speakeasyapi.dev if you are interested in a performance benchmark.

Integrate wth your API gateway

Configure Speakeasy as a native integration (OIDC) with your API gateway by using an OpenAPI securityDefinition. We will validate incoming API requests against customer API keys. We will manage a 1:1:1 relationship between Customer API keys:JWT Signing Keys:JWK Public Keys. Note that most API Gateways have a stated propagation time that could be upto a few minutes. After a key is revoked by a user in a dev portal, API requests for that key will no longer hit your application server and will be terminated at the API gateway.

Update your API configuration

Open your OpenAPI spec file and add a new securityDefinitions section. In this section, add a new definition speakeasy_api_key with the following fields:

Security Definitions
| Field                | Type
|----------------------|-----------------|
| authorizationUrl | The authorization URL, should be set to "". |
| flow | The flow used by the OAuth2 security scheme. Should be set to "implicit". |
| type | The type of the security scheme. Should be set to "oauth2" |
| x-google-issuer | The issuer of a credential, should be set to "https://app.speakeasyapi.dev/v1/auth/oauth/{your-speakeasy-worksapce-id}" |
| x-google-jwks_uri | The URI of the public key set to validate the JSON Web Token (JWT) signature. Set this to "https://app.speakeasyapi.dev/v1/auth/oauth/{your-speakeasy-workspace-id}/.well-known/jwks.json". |
| x-google-audiences | Your Speakeasy workspace idenfitifer. |

A sample security definition is shown below:

securityDefinitions:
speakeasy_api_key:
authorizationUrl: ""
flow: "implicit"
type: "oauth2"
x-google-issuer: "https://app.speakeasyapi.dev/v1/auth/oauth/{your-speakeasy-worksapce-id}"
x-google-jwks_uri: "https://app.speakeasyapi.dev/v1/auth/oauth/{your-speakeasy-workspace-id}/.well-known/jwks.json"
x-google-audiences: "acme-company"

Your workspace id can be found in the Speakeasy Dashboard. The easies way to do so would be to look at the URL when you are in your workspace: https://app.speakeasyapi.dev/workspaces/self. In this example it would be self.

Update the Endpoint

Now, update the endpoint by adding a security field with the securityDefinition we created in the previous step.

paths:
"/hello":
get:
description: "Responds with hello world."
operationId: "helloworld"
produces:
- "application/json"
responses:
200:
description: "Hello World message"
schema:
$ref: "#/definitions/helloMessage"
security:
- speakeasy_api_key: []

In the above example, the security field tells the gateway proxy that our /hello path expects to be secured with the speakeasy_api_key definition.

Here is a complete example for Google Endpoints of how you would add this securityDefinition to your OpenAPI spec:

swagger: "2.0"
info:
description: "A simple Google Cloud Endpoints API example."
title: "Hello World Example"
version: "1.0.0"
host: "${endpoints_host}"
# [END swagger]
consumes:
- "application/json"
produces:
- "application/json"
schemes:
# Uncomment the next line if you configure SSL for this API.
#- "https"
- "http"
x-google-backend:
address: "${backend_service_addr}"
protocol: h2
paths:
"/hello":
get:
description: "Responds with hello world."
operationId: "helloworld"
produces:
- "application/json"
responses:
200:
description: "Hello World message"
schema:
$ref: "#/definitions/helloMessage"
security:
- speakeasy_api_key: []
definitions:
helloMessage:
type: "object"
properties:
message:
type: "string"
securityDefinitions:
speakeasy_api_key:
authorizationUrl: ""
flow: "implicit"
type: "oauth2"
x-google-issuer: "https://app.speakeasyapi.dev/v1/auth/oauth/{your-speakeasy-worksapce-id}"
x-google-jwks_uri: "https://app.speakeasyapi.dev/v1/auth/oauth/{your-speakeasy-workspace-id}/.well-known/jwks.json"
x-google-audiences: "acme-company"

Optionally, if you self-host Speakeasy, the x-***-issuer and x-***-jwks-uri would be accessed completely within your Kubernetes instance.

Setting Custom JWT Claims

You can leverage the Speakeasy serverside SDKs to set custom claims on the JWT signing key that is generated for each API key. A custom claim allows Speakeasy to look for certain fields in the JWT that you may want to use for verifying identity. This could be something as simple as a user_id or an email.

Use the getPortalLoginToken method exposed by the Speakeasy middleware to pass in a string map of desired claims. Here is an example method you could add to your API for setting claims for user_id and email using our Java SDK. Please refer to each SDKs documentation for more details on available methods.

@Get("/speakeasy_portal_login_token")
public String getPortalLoginAccessToken(@RequestAttribute(SpeakeasyMiddlewareController.Key) SpeakeasyMiddlewareController controller){
String customerId="some-customer-id";
// Restrict data by time (last 24 hours)
Instant startTime=Instant.now().minusSeconds(60*60*24);
filterBuilder.withTimeFilter(startTime,SpeakeasyAccessTokenFilterOperator.GreaterThan);

// Populate with any custom claims you want added to your created API keys
Map<String, String> jwtCustomClaims = new HashMap<>();
jwtCustomClaims.put("user_id", "your-desired-user_id")
jwtCustomClaims.put("email", "your-desired-email")

// Populate with any permissions you want enabled/disabled for the user
Map<String, Boolean> permissions = new HashMap<>();
permissions.put("end_user:api_keys:read", true)
String accessToken=controller.getPortalLoginToken(customerId, "Some User Display Name", jwtCustomClaims,
permissions, filterBuilder.build());
// build response
}

In this example the custom claims set are for user_id and email. These claims will be added to the JWT signing key that is generated for each API key. Your customers will now be able to self service the management of API keys.

Setting custom permissions for portal users

You may want to control what permissions users have in your portal. For example, you may want to restrict users from creating API keys. You can do this by populating the permissions map via the getPortalLoginToken method. In this example, we are enabling users to create API keys with the end_user:api_keys:write permission. Currently supported permissions for API key management are end_user:api_keys:read and end_user:api_keys:write.

If you are an admin on your workspace (likely only your internal dev team) than you will be able to create and revoke API keys on behalf of your end users. In the developer portal you'll see an "as Admin" suffix in the left hand side nav bar to indicate your admin level of access. On the API key management page you'll notice a drop down to filter keys by Customer ID that will allow you filter keys by customer. This is useful if you have multiple customers using your API and you would like to revoke or create keys for a specific customer.

admin-api-keys