Customize Security & Authentication
Authentication Overview
Speakeasy-created SDKs have authentication configured automatically based on the securitySchemes
defined in your OpenAPI specification.
For APIs authenticated by long-lived tokens (API keys), these should work out of the box. For APIs authenticated by short-lived tokens (OAuth), extra configuration is required to minimize your users' effort.
Support for securitySchemes
In your OpenAPI specification, define the securitySchemes
object according to your API's authentication mechanism.
Authentication Mechanism | Language Support |
---|---|
HTTP Basic Authentication | ✅ All Languages |
API Key [header] | ✅ All Languages |
API Key [cookie] | ✅ All Languages |
API Key [query param] | ✅ All Languages |
API Key [Bearer] | ✅ All Languages |
OAuth Implicit Flow | ✅ All Languages |
OAuth Refresh Token Flow | 🏗️ Partial |
OAuth Client Credentials Flow | 🏗️ Partial |
mTLS | 🏗️ Partial |
HTTP Basic Authentication
Supported in all languages. Defining basic
authentication will prompt users for a username and password when instantiating the SDK.
paths: /drinks: get: operationId: listDrinks summary: Get a list of drinks. description: Get a list of drinks, if authenticated this will include stock levels and product codes otherwise it will only include public information. tags: - drinkscomponents: securitySchemes: auth: type: http scheme: basicsecurity: - auth: []
const s = sdk.SDK( (security = shared.Security( (username = "..MY_USER.."), (password = "..MY_PASSWORD..") )));await s.list_drinks();
API Key Authentication
Supported in all languages. Defining api_key
authentication will prompt users for a key when instantiating the SDK. How the key is passed to your API will be abstracted from your users. Speakeasy supports passing the key as a header, cookie, query param, or bearer token.
paths: /drinks: get: operationId: listDrinks summary: Get a list of drinks. description: Get a list of drinks, if authenticated this will include stock levels and product codes otherwise it will only include public information. tags: - drinkscomponents: securitySchemes: api_key: type: apiKey name: api_key in: headersecurity: - api_key: []
const s = new SDK({ security: { apiKey: "..MY_KEY.." } });await s.drinks.listDrinks();
OAuth
Speakeasy supports OAuth authentication in the most popular languages. Support for additional languages is coming soon.
Typescript | Python | Go | C# | Java | PHP | Swift | Ruby |
---|---|---|---|---|---|---|---|
✅ | ✅ | ✅ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ |
Enabling OAuth security in your SDK currently requires additional configuration outside of your OpenAPI spec.
Step 1: Define OAuth Security in Your OpenAPI Spec
Our current OAuth support does not use the OpenAPI description, but native support is on the way, so don't skip this step!
/oauth2/token: get: operationId: auth security: - [] responses: 200: description: OK content: application/json: schema: type: object properties: access_token: string required: - access_token /example: get: operationId: example responses: 200: description: OKcomponents: securitySchemes: auth: type: oauth2 flows: clientCredentials: tokenUrl: https://speakeasy.bar/oauth2/token/ scopes: {}security: - auth: []
Step 2: Add Your Callback Function to Your SDKs
To implement OAuth authentication, you need to write a callback function to handle your OAuth token exchange. To do so, add a file to your SDKs src
folder called oauth.ts
(or oauth.py
for Python, oauth.go
for Go, and so on):
import axios from "axios";// eslint-disable-next-line @typescript-eslint/no-unused-varsexport function withAuthorization(clientID: string, clientSecret: string) { return async (): Promise<{ oauth2: string }> => { const tokenEndpoint = "https://speakeasy.bar/oauth2/token/"; const data = { grant_type: "client_credentials", client_id: clientID, client_secret: clientSecret, }; try { const response = await axios.post(tokenEndpoint, data); return { oauth2: response.data.access_token }; } catch (error) { throw new Error("Failed to obtain OAuth token"); } };}
Step 3: Pass Callback Function in SDK Instantiation
Edit your Readme
to instruct users to pass in the callback function when instantiating the SDK. We recommend adding a custom OAuth section that shows users how to instantiate their SDK via the callback function:
const sdk = new SDK({ security: withAuthorization("client_id", "client_secret"),});await s.listDrinks();
Scoping Authentication
Global
Global security allows your users to configure the SDK once and reuse the security configuration for all subsequent calls.
To use global security, define your security configuration in the security
block at the root of the SDK.
paths: /drinks: get: operationId: listDrinks summary: Get a list of drinks. description: Get a list of drinks, if authenticated this will include stock levels and product codes otherwise it will only include public information. tags: - drinkscomponents: securitySchemes: api_key: type: apiKey name: api_key in: headersecurity: # Here - api_key: []
In the resulting SDK, the user will be able to define the security configuration in the SDK's instantiation. It will then be automatically applied to all subsequent method calls without needing to be passed in as an argument:
const s = new SDK({ security: { apiKey: "..MY_KEY.." } });await s.drinks.listDrinks();
Per-Operation
NOTE
Security Hoisting: In cases where global security is not defined, we will automatically hoist the most commonly occurring operation-level security to be considered global. This will simplify the usage of your SDK.
Operation-specific security configuration allows for overriding one endpoint's authentication configuration.
This is most often used for operations that do not require authentication, or when an operation is part of an authentication flow (for example, invoked to retrieve a shorter-lived access token).
To use operation-specific security, define security
within an operation's scope.
paths: /drinks: get: operationId: listDrinks summary: Get a list of drinks. description: Get a list of drinks, if authenticated this will include stock levels and product codes otherwise it will only include public information. security: - apiKey: [] tags: - drinkscomponents: securitySchemes: api_key: type: apiKey name: api_key in: header
In the SDK, the user will be able to pass in a specific security configuration as an argument to the method call:
const sdk = new SDK();const operationSecurity: ListDrinksSecurity = { apiKey: "",};sdk.drinks.listDrinks(operationSecurity).then((res: ListDrinksResponse) => { if (res.statusCode == 200) { // handle response }});
Flattened Global Security
The flattened global security feature only works if you have a single global security scheme. We provide an option for flattening down the security parameters to pass. This is a small change, but it can be helpful for APIs with a straightforward security configuration. To enable flattened global security, set the flattenGlobalSecurity
field to true
in your SDK repo gen.yaml
:
Here's a demonstration of what code in such a situation might look like without and then with flattening:
// Without global security flattening enabledconst s = new SDK({ security: { apiKey: "..MY_KEY.." } });await s.drinks.listDrinks();// With global security flattening enabledconst s = new SDK({ apiKey: "..MY_KEY.." });await s.drinks.listDrinsk();