Build your first integration
This guide takes a user from your login button to an authenticated Vyde API request. The examples use one flow; select the language you are using in each step.
How the flow works
Section titled “How the flow works”sequenceDiagram participant App as Your application participant Browser participant Vyde as Vyde Identity participant API as Vyde API App->>App: Generate state and PKCE verifier App->>Browser: Redirect to authorization Browser->>Vyde: Login and consent Vyde–>>Browser: Redirect with code and state Browser->>App: Callback App->>App: Verify state App->>Vyde: POST token Vyde–>>App: Access and refresh tokens App->>API: Bearer access token API–>>App: Delegated response
Before you start
Section titled “Before you start”- Create an application in the Identity Console.
- Choose Public for a browser, mobile, desktop, or CLI app. Choose Confidential for a server-side app.
- Register the exact callback URL used by your application.
- Enable
authorization_code,refresh_token, and only the scopes you need.
Developer settings: endpoints and local environments
Production authorization endpoint: https://identity.vyde.dev/oauth2/authorize.
Production token and API base: https://api.vyde.dev.
Use /.well-known/openid-configuration instead of hardcoding endpoint paths in a reusable
integration. Local development uses the .test hosts configured by your project.
1. Start the authorization request
Section titled “1. Start the authorization request”Generate both values for every login attempt. Store state and verifier in the user’s
server-side login transaction; do not put the verifier in a URL or browser storage.
import crypto from 'node:crypto';
const state = crypto.randomBytes(32).toString('base64url');
const verifier = crypto.randomBytes(32).toString('base64url');
const challenge = crypto.createHash('sha256').update(verifier).digest('base64url');
// Store state and verifier in the user's server-side login transaction.
const params = new URLSearchParams({
response_type: 'code',
client_id: process.env.VYDE_CLIENT_ID!,
redirect_uri: 'https://app.example.com/oauth/callback',
scope: 'openid profile email',
state,
code_challenge: challenge,
code_challenge_method: 'S256',
});
const authorizationUrl = `https://identity.vyde.dev/oauth2/authorize?${params}`;import base64, hashlib, secrets
from urllib.parse import urlencode
state = secrets.token_urlsafe(32)
verifier = secrets.token_urlsafe(32)
challenge = base64.urlsafe_b64encode(
hashlib.sha256(verifier.encode()).digest()
).rstrip(b"=").decode()
# Store state and verifier in the user's server-side login transaction.
authorization_url = "https://identity.vyde.dev/oauth2/authorize?" + urlencode({
"response_type": "code",
"client_id": os.environ["VYDE_CLIENT_ID"],
"redirect_uri": "https://app.example.com/oauth/callback",
"scope": "openid profile email",
"state": state,
"code_challenge": challenge,
"code_challenge_method": "S256",
})use base64::{engine::general_purpose::URL_SAFE_NO_PAD, Engine};
use rand::RngCore;
use sha2::{Digest, Sha256};
let mut bytes = [0u8; 32];
rand::thread_rng().fill_bytes(&mut bytes);
let state = URL_SAFE_NO_PAD.encode(bytes);
rand::thread_rng().fill_bytes(&mut bytes);
let verifier = URL_SAFE_NO_PAD.encode(bytes);
let challenge = URL_SAFE_NO_PAD.encode(Sha256::digest(verifier.as_bytes()));
// Store state and verifier in the user's server-side login transaction.# Use values generated by your application; do not use predictable placeholders in production.
curl -G 'https://identity.vyde.dev/oauth2/authorize' \
--data-urlencode 'response_type=code' \
--data-urlencode 'client_id=YOUR_CLIENT_ID' \
--data-urlencode 'redirect_uri=https://app.example.com/oauth/callback' \
--data-urlencode 'scope=openid profile email' \
--data-urlencode 'state=GENERATED_STATE' \
--data-urlencode 'code_challenge=BASE64URL_SHA256_VERIFIER' \
--data-urlencode 'code_challenge_method=S256'Redirect the user’s browser to authorizationUrl. Vyde authenticates the user and displays
consent when required.
2. Handle the callback
Section titled “2. Handle the callback”Vyde redirects to the registered URI:
https://app.example.com/oauth/callback?code=ONE_TIME_CODE&state=GENERATED_STATE
Compare the returned state with the server-side value before doing anything else. If it differs,
discard the callback and do not exchange the code. On denial, handle error, error_description,
and state without attempting a token exchange.
3. Exchange the code
Section titled “3. Exchange the code”The request is form-encoded. Public clients omit client_secret; confidential clients send it only
from their backend.
const response = await fetch('https://api.vyde.dev/oauth2/token', {
method: 'POST',
headers: { 'content-type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({
grant_type: 'authorization_code', code, client_id: clientId,
redirect_uri: redirectUri, code_verifier: verifier,
}),
});
const tokens = await response.json();tokens = requests.post("https://api.vyde.dev/oauth2/token", data={
"grant_type": "authorization_code", "code": code,
"client_id": client_id, "redirect_uri": redirect_uri,
"code_verifier": verifier,
}, timeout=15).json()let tokens = reqwest::Client::new()
.post("https://api.vyde.dev/oauth2/token")
.form(&[("grant_type", "authorization_code"), ("code", code),
("client_id", client_id), ("redirect_uri", redirect_uri),
("code_verifier", verifier)])
.send().await?;curl -X POST 'https://api.vyde.dev/oauth2/token' \
-H 'content-type: application/x-www-form-urlencoded' \
--data-urlencode 'grant_type=authorization_code' \
--data-urlencode 'code=ONE_TIME_CODE' \
--data-urlencode 'client_id=YOUR_CLIENT_ID' \
--data-urlencode 'redirect_uri=https://app.example.com/oauth/callback' \
--data-urlencode 'code_verifier=YOUR_PKCE_VERIFIER'4. Call the API
Section titled “4. Call the API”Use the access token as a bearer token. Never send a refresh token to an API resource.
curl https://api.vyde.dev/v1/accounts/me \
-H 'authorization: Bearer ACCESS_TOKEN'
The response contains the requested resource. See the API reference for request bodies, response shapes, and error handling.