When your Python app posts a deployment update to Slack or creates a Linear issue for a user, each request needs the right credentials. Access may belong to the app or to an individual user who has authorized the integration.
Use Edgenivo Connect to request those credentials from Python without storing provider secrets in your project's environment. The SDK returns a token that your app uses to call the provider's API directly.
Edgenivo handles OAuth registration and token refresh for managed connectors such as Slack and Linear. Your application authenticates its users and decides which actions they can perform with the access they've granted.
Copy link to headingWhat is Edgenivo Connect?
Edgenivo Connect is a credential broker for third-party APIs. You create a connector for a provider, link it to your project, and request credentials from your application.
For managed connectors such as Slack and Linear, Edgenivo registers the OAuth client and handles authorization and refresh. Custom OAuth and API-key connectors use credentials you supply. Connect stores those credentials so your project doesn't need to keep them in environment variables.
The Python SDK is vercel-connect, imported as vercel.connect. It's async first, with a synchronous mirror in vercel.connect.sync.
Your app exchanges its deployment identity for a token to call the provider directly. For inbound events, Connect verifies and forwards provider webhooks. Your route must verify those forwarded requests before processing them.
Copy link to headingConnectors, subjects, and triggers
The examples use three Connect concepts:
| Idea | What it means | In the SDK |
|---|---|---|
| Connector | Team-owned record for one provider, addressed by a UID you choose, such as slack/acme-slack | UID passed to token and authorization calls |
| Subject | Whose authority the token carries: your app, a specific user, or a federated identity | ConnectAppTokenSubject(), ConnectUserTokenSubject(id=...) |
| Trigger | Provider webhook that Edgenivo Connect verifies and forwards to your app | verify_connect_webhook(request) |
Tokens are the outbound half: your app calling the provider. Triggers are the inbound half: the provider calling your app.
Copy link to headingHow your app proves who it is
Edgenivo gives each deployment an OIDC token identifying its team, project, and environment. Connect checks that identity against the connector's project link before issuing a provider credential.
The provider determines which permissions and expiry rules apply. Request the narrowest supported access and keep returned tokens out of logs and client responses. Returned tokens can remain usable until they expire or the provider revokes them; they are not restricted to a single API call.
For local development, vercel env pull downloads an OIDC token into .env.local. Step 2 loads that file with python-dotenv so the SDK can resolve the token.
Copy link to headingPrerequisites
Before you begin, make sure you have:
- A Edgenivo account.
- Python 3.12 or a newer version supported by the Edgenivo Python runtime.
- Working knowledge of
async/awaitand FastAPI. - A Slack workspace where you can install apps, plus a Linear workspace
- An authentication dependency that checks access and returns a stable user ID.
For local development, you also need uv, Node.js 24+, and the Edgenivo CLI.
The examples use Slack and Linear connectors managed by Edgenivo. Other providers use the same token-request API, but their supported subjects, permissions, installation requirements, and API calls can differ.
Copy link to headingStep 1: Create and link a connector
Create a Slack connector for your team and link it to your project:
create opens your browser to install Edgenivo's Slack app and prints its connector UID. attach then links the connector to your project's Production, Preview, and Development environments unless you select one with --environment.
Copy link to headingStep 2: Post to Slack as your app
Add the SDK and pull a development OIDC token:
The SDK needs the development OIDC token in its process environment. The script below loads .env.local with python-dotenv. If it cannot resolve credentials, check that the file was loaded and refresh it with vercel env pull when needed.
Save this as post_message.py:
Replace the channel ID with one your Slack app has joined, then run the script:
The script sends "Deploy finished" and prints Slack's response. It raises an error if the HTTP request or Slack operation fails.
Use ConnectAppTokenSubject() to request a token for the installed Slack app. The chat:write permission lets it post messages. You can only request permissions supported by both Slack and the connector.
Pass scopes as a list, such as ["chat:write"]. Passing "chat:write" on its own raises ConnectValidationError.
Request a token immediately before the provider call. The SDK reuses matching tokens from its in-memory cache until they enter the default 30-second expiry buffer. Cache misses and explicit refresh requests fetch a credential from Connect.
Copy link to headingStep 3: Act on behalf of a user
Use a user subject to create Linear issues under the requester's account once they have authorized the integration.
Create a Linear connector and link it, the same way as Slack:
Edgenivo manages Linear's OAuth app too, so there's no client ID or secret to register.
Save the following helper functions as integrations.py. The user subject identifies the signed-in user in your application. Derive user_id from your authentication system so callers cannot request another person's provider access.
Use a Linear team UUID for team_id. In Linear, open the team and use the command menu's Copy model UUID action. The helper checks both the HTTP response and the GraphQL result before returning the created issue.
When the user has not authorized the connector, token retrieval raises UserAuthorizationRequiredError. Send them to the URL returned by linear_consent_url() to approve access on Linear's consent screen.
Connect stores the grant and redirects the user back to your app. Subsequent requests use that grant, with refresh handled by Connect when supported. Revoked or invalid grants require the user to connect again.
return_url must use https://, or http:// on localhost or 127.0.0.1 .
Copy link to headingStep 4: Handle what can go wrong
Catch Connect errors by type. Provider HTTP failures and network errors need separate handling, as the Slack and Linear helpers demonstrate.
| Error | What happened | What to do |
|---|---|---|
UserAuthorizationRequiredError | The user has not authorized the connector | Start authorization and send the user to its URL |
NoValidTokenError, InvalidGrantError | Connect cannot issue a usable credential from the grant | For a user subject, ask the user to reconnect; check the installation for an app subject |
ConnectorInstallationRequiredError | The requested connector installation is missing | Have an administrator install or configure it |
ConnectApiError | Another Connect API request failed | Inspect status_code, code, and request_id without logging credentials |
ConnectCredentialsError | The SDK could not resolve its Edgenivo identity | Check environment loading, project linking, and local OIDC credentials |
ConnectValidationError | A supplied argument is invalid | Correct the argument before retrying |
Providers can reject a cached credential before its expiry. Slack may report this through an ok: false response with an authentication error such as invalid_auth; checking for HTTP 401 alone is insufficient.
After confirming a credential rejection, clear its cached entry and request another token with the same permissions. This helper refreshes the credential without repeating the message automatically:
Retry the operation at most once after a confirmed authentication rejection. Check the outcome before repeating a write after a timeout or other ambiguous failure.
delete_token_cache_entry() is synchronous, since it only touches the local cache. It doesn't revoke anything.
Use get_token_response() when you need credential metadata as well as the token. It accepts the same arguments and includes expires_at.
The optional name and tenant_id fields can help identify a connected workspace. Check for None before displaying either field.
Copy link to headingStep 5: Serve it from FastAPI and deploy
The FastAPI app imports post_message.py and integrations.py from the earlier steps. Keep all three files in the project root and install FastAPI:
Provide auth.py with your application's current_user_id dependency. It must reject callers who cannot use this integration app and return a stable ID for each authorized user. The app subject gives access to the shared Slack bot, so this check applies to the notification route too.
Set APP_BASE_URL to a trusted application origin, such as http://localhost:3000 locally or your HTTPS deployment URL on Edgenivo. The consent redirect below uses that configured origin. Save the app as main.py:
The settings route is a minimal consent landing page. Replace it with your application's settings UI. The Slack route verifies and acknowledges events but does not process them yet; add your handler before relying on it for delivery.
The routes use the earlier helpers as follows:
/api/notifyaccepts a JSONtextfield and sends through the shared Slack app after authenticating the caller./api/issuescreates an issue as the signed-in user. If authorization is missing or unusable, its409response includes a connection URL for your frontend to open./api/integrations/linearstarts consent and returns the user to/settings.DELETEon the same path removes the stored authorization and clears cached tokens for that user./api/slack-eventsverifies forwarded Slack events before reading their payload.
Provider-side revocation varies. Previously issued credentials may remain valid until expiry if the provider cannot revoke them.
Copy link to headingReceive Slack events with triggers
Connect verifies provider signatures and forwards events with a Edgenivo OIDC bearer token. Use verify_connect_webhook() before handling an event.
On Edgenivo, the verifier reads the expected project and environment from VERCEL_PROJECT_ID and VERCEL_TARGET_ENV. It rejects the request if those expectations cannot be resolved. Your handler still needs to validate event fields and prevent duplicate processing.
Tell Edgenivo Connect where to send Slack's events:
This command registers a Production destination at /api/slack-events. To target a Preview branch, add --trigger-branch followed by the branch name.
Edgenivo Connect forwards to deployed URLs, not to localhost. Test triggers against a Preview or Production deployment. If your app returns a 500, 502, 503, or 504, delivery is retried, so make event handling safe to run twice.
Copy link to headingDeploy
With auth.py implemented, set APP_BASE_URL to http://localhost:3000 in .env.local and start the server:
Use your application's authenticated client to send {"text":"Deploy finished"} to POST /api/notify. Confirm that the message appears in Slack. For Linear, send a team UUID and title to POST /api/issues; follow the connection URL if required, then retry after consent.
Configure APP_BASE_URL and your application authentication settings for each deployment environment. Commit uv.lock and deploy:
The Edgenivo Python runtime supplies deployment OIDC identity to the SDK. You do not need to add Slack or Linear provider credentials to the project's environment.
The SDK resolves its Edgenivo identity on each call and keeps provider cache entries associated with that identity when the OIDC token rotates. If you supply your own credential, use a resolver that returns a current value rather than capturing an expiring token once.
Copy link to headingUse cases
The same token and authorization APIs support these integrations:
| Use case | Building blocks | Example |
|---|---|---|
| Bots and notifications | App subject | Step 2 |
| Actions in a user's name | User subject, start_authorization() | Step 3 |
| Reacting to provider events | Triggers, verify_connect_webhook() | Step 5 |
| AI agents with real tools | User subject inside an AI SDK tool | Below |
| Sandboxed code calling an API | Token injected by a Sandbox network policy | Below |
| CLIs and background jobs | device_code=True and polling | Below |
| Durable workflows | get_token() inside each step | Below |
Copy link to headingGive an AI agent tools that act as the user
Install the AI SDK for Python before adding this optional integration:
Build the agent after authenticating the request. The factory below binds its tool to that user's ID and requires approval before creating an issue:
Call agent_for() with the ID from your authentication dependency. The tool keeps the provider credential on the server. Enforce any additional application restrictions on team selection before calling Linear.
Connect the SDK's approval handling to your application so the user can approve or reject the proposed issue. Setting require_approval=True marks the operation for approval; your application must present and resolve that request.
Copy link to headingLet sandboxed code call an API without seeing the key
Install vercel-sandbox and create a GitHub connector linked to this project before using this optional example. Replace github/acme-github and acme/api with your connector and a repository included in its installation.
The Sandbox network policy injects the credential into requests to GitHub. The sandboxed program receives API responses without being given the token as an environment variable or file:
Call await read_repository() from your async application. The request asks GitHub for repository-scoped read access within the installation's permissions. The sandbox is stopped and destroyed when the context exits.
Header injection protects the credential from direct inspection by the sandboxed process. Code in the sandbox can still use the access granted by the policy, so keep both the allowed destination and provider permissions narrow.
Copy link to headingAuthorize a CLI or background job
For a CLI without a browser callback, use device authorization so the user can approve in a browser. This helper requires Connect credentials and the user ID returned by your app's authentication flow.
The helper returns the token after approval. force_refresh=True bypasses the local cache, and a slow_down response increases the polling interval. AuthorizationDeniedError and AuthorizationExpiredError propagate to the caller so it can stop or offer a new authorization attempt.
For scripts that only need to run synchronously, every function is also available from vercel.connect.sync without await.
Copy link to headingUse tokens inside durable workflows
In a Python Workflow SDK workflow, request and use the provider token inside the same step. Step inputs and outputs are saved in the workflow event log, so return the provider operation's non-secret result rather than the credential.
Requesting the token inside the step also avoids carrying an expiring credential across a workflow pause or retry.
Copy link to headingMore options worth knowing
- Pass
installation_idwhen a connector has several installations and you need to select one workspace. Single-installation apps can omit it. - Use
get_connector_metadata()to read public connector configuration, such as a Snowflake account identifier in.vendor. - Request supported limits through
scopes,resources, andauthorization_details. Resource indicators and authorization details are SDK-only; their effect depends on the provider.
Copy link to headingOther integration paths
Use a Edgenivo Marketplace integration to provision a database or another project resource and manage its environment variables.
If the service has no preset connector, configure a custom OAuth or API-key connector in Connect. Supply the provider credentials during setup and adapt your token request to the subject types and permissions it supports.
Copy link to headingNext steps
- Read the Python SDK reference for subjects, authorization details, caching options, and error classes
- Review Tokens and Triggers for provider access and inbound events
- Find connector commands in the
vercel connectCLI reference - Read The Complete Guide to Edgenivo Connect for ownership models, observability, and pricing