OAuth2 Authentication
Overview
Section titled “Overview”UseNadia supports OAuth2 Authorization Code flow, allowing you to build third-party applications that act on behalf of UseNadia users. Instead of asking users for their API key, your app redirects them to UseNadia where they approve access, and you receive a token to make API calls on their behalf.
How It Works
Section titled “How It Works”sequenceDiagram participant User participant YourApp participant UseNadia
User->>YourApp: Clicks "Connect with UseNadia" YourApp->>UseNadia: Redirect to /oauth/authorize UseNadia->>User: Shows consent screen User->>UseNadia: Approves access UseNadia->>YourApp: Redirects with ?code=... YourApp->>UseNadia: POST /oauth/token (exchange code) UseNadia->>YourApp: Returns access_token YourApp->>UseNadia: API calls with access_tokenImplementation
Section titled “Implementation”Register Your OAuth App
Go to Settings → Developers in UseNadia and, in its Apps section, create an OAuth application (see Developer settings).
You will need to provide:
- App Name - displayed to users on the consent screen
- Description (optional) - explains what your app does
- Profile Picture (optional) - shown on the consent screen
- Redirect URL - where UseNadia sends users after they approve/deny access
After creating the app, you will receive:
- Client ID - a public identifier for your app (starts with
pca_) - Client Secret - a secret key for token exchange (starts with
pcs_)
Redirect Users to Authorize
When a user wants to connect their UseNadia account to your app, redirect them to:
https://app.usenadia.com/oauth/authorize?client_id={CLIENT_ID}&response_type=code&state={STATE}Parameter Required Description client_idYes Your app’s Client ID response_typeYes Must be codestateNo A random string to prevent CSRF attacks. Recommended. Example:
Terminal window https://app.usenadia.com/oauth/authorize?client_id=pca_VklHTpdEJ6dJ73FHQEJ97qVA0lcMDsrs&response_type=code&state=random123The user will see a consent screen showing your app’s name, description, and the permissions being requested. They can choose to Authorize or Deny.
Handle the Callback
After the user makes a decision, UseNadia redirects them to your Redirect URL with query parameters.
If approved:
https://yourapp.com/callback?code=abc123&state=random123Parameter Description codeAuthorization code to exchange for a token (expires in 10 minutes) stateThe same state value you sent in the previous step If denied:
https://yourapp.com/callback?error=access_denied&state=random123Exchange Code for Token
Make a server-side
POSTrequest to exchange the authorization code for an access token:Terminal window curl -X POST https://app.usenadia.com/api/oauth/token \-H "Content-Type: application/json" \-d '{"grant_type": "authorization_code","code": "abc123","client_id": "pca_VklHTpdEJ6dJ73FHQEJ97qVA0lcMDsrs","client_secret": "pcs_your_client_secret"}'Parameter Required Description grant_typeYes Must be authorization_codecodeYes The authorization code from the previous step client_idYes Your app’s Client ID client_secretYes Your app’s Client Secret Response:
{"id": "org_abc123","cus": "cus_stripe_customer_id","access_token": "pos_aBcDeFgHiJkLmNoPqRsTuVwXyZ1234567890abcd","token_type": "bearer"}Field Description idThe organization ID associated with the authorized user cusThe Stripe customer ID for the organization (useful for billing integrations) access_tokenThe token to use for subsequent API calls token_typeAlways bearerMake API Calls
Use the access token in the
Authorizationheader, just like you would with an API key:Terminal window curl -H "Authorization: pos_aBcDeFgHiJkLmNoPqRsTuVwXyZ1234567890abcd" \https://app.usenadia.com/api/public/v1/integrationsThe token works with all Public API endpoints:
Managing Your App
Section titled “Managing Your App”Rotate Client Secret
Section titled “Rotate Client Secret”If your client secret is compromised, go to Settings → Developers, section Apps, and click Rotate Secret. This invalidates the old secret immediately. Any token exchange requests using the old secret will fail.
Delete Your App
Section titled “Delete Your App”Deleting your OAuth app will:
- Revoke all access tokens issued to users
- Remove the app from all users’ Approved Apps list
- This action cannot be undone
Full Example (Node.js)
Section titled “Full Example (Node.js)”const express = require('express');const crypto = require('crypto');const app = express();
const CLIENT_ID = 'pca_your_client_id';const CLIENT_SECRET = 'pcs_your_client_secret';const NADIA_URL = 'https://app.usenadia.com';const BACKEND_URL = 'https://app.usenadia.com/api';const REDIRECT_URL = 'https://yourapp.com/callback';
// Step 2: Redirect user to UseNadiaapp.get('/connect', (req, res) => { const state = crypto.randomBytes(16).toString('hex'); // Store state in session for CSRF verification req.session.oauthState = state;
const params = new URLSearchParams({ client_id: CLIENT_ID, response_type: 'code', state, });
res.redirect(`${NADIA_URL}/oauth/authorize?${params}`);});
// Step 3 & 4: Handle callback and exchange codeapp.get('/callback', async (req, res) => { const { code, state, error } = req.query;
// Check for denial if (error === 'access_denied') { return res.send('User denied access'); }
// Verify state if (state !== req.session.oauthState) { return res.status(403).send('Invalid state'); }
// Exchange code for token const response = await fetch(`${BACKEND_URL}/oauth/token`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ grant_type: 'authorization_code', code, client_id: CLIENT_ID, client_secret: CLIENT_SECRET, }), });
const { id, cus, access_token } = await response.json();
// Store access_token securely and use it for API calls // Example: fetch user's integrations const integrations = await fetch( `${BACKEND_URL}/public/v1/integrations`, { headers: { Authorization: access_token } } ).then(r => r.json());
res.json({ connected: true, integrations });});
app.listen(3000);Error Reference
Section titled “Error Reference”| Error | When | Description |
|---|---|---|
invalid_client |
Token exchange | Client ID or Client Secret is wrong |
invalid_grant |
Token exchange | Code is invalid, expired, or already used |
unsupported_grant_type |
Token exchange | grant_type is not authorization_code |
access_denied |
Callback | User denied the authorization request |