luduvo.py
A Python library for interacting with the Luduvo API.
It provides a simple interface for Luduvo API requests, OAuth 2.0 authentication, PKCE, OAuth application management, token exchange, and authenticated user information.
Features
- Luduvo API client
- Bearer token authentication
- OAuth application creation
- OAuth application listing
- OAuth application deletion
- OAuth 2.0 authorization
- PKCE authentication
- Authorization code exchange
- Authenticated user information
- Simple Python API
- Automatic JSON request handling
Installation
Install the package from PyPI:
python -m pip install luduvo.py
Upgrade to the latest version:
python -m pip install --upgrade luduvo.py
Import the package:
from luduvo import Luduvo
Requirements
- Python 3.9+
- requests
requests is installed automatically when installing the package.
Basic Usage
Create a client without authentication:
from luduvo import Luduvo
client = Luduvo()
Or provide a Luduvo API token:
from luduvo import Luduvo
client = Luduvo("YOUR_LUDUVO_TOKEN")
The API base URL is:
https://api.luduvo.com
When a token is provided, authenticated requests automatically use:
Authorization: Bearer YOUR_LUDUVO_TOKEN
OAuth
luduvo.py provides helpers for the Luduvo OAuth 2.0 authorization flow with PKCE.
The OAuth flow is:
Create OAuth Application
│
▼
Generate PKCE verifier
│
▼
Generate PKCE challenge
│
▼
Create authorization URL
│
▼
User signs into Luduvo
│
▼
User authorizes application
│
▼
Luduvo redirects to callback
│
▼
Receive authorization code
│
▼
Exchange code + verifier
│
▼
Receive access token
│
▼
Request /oauth/userinfo
OAuth Application Management
Creating an OAuth Application
OAuth applications can be created through the Luduvo API.
from luduvo import Luduvo
client = Luduvo("YOUR_LUDUVO_TOKEN")
app = client.oauth.create(
name="My Luduvo App",
description="An application using Luduvo OAuth.",
redirect_uris=[
"http://localhost:3000/callback"
],
is_confidential=True
)
print(app)
A response will contain information similar to:
{
"id": 5,
"client_id": "ldv_b748212bcc097120d2bfac589a6977dd",
"name": "My Luduvo App",
"description": "An application using Luduvo OAuth.",
"redirect_uris": [
"http://localhost:3000/callback"
],
"is_confidential": true,
"created_at": 1790751617,
"updated_at": 1790751617
}
create_oauth()
create_oauth() is an alias for create().
from luduvo import Luduvo
client = Luduvo("YOUR_LUDUVO_TOKEN")
app = client.oauth.create_oauth(
name="My Luduvo App",
description="An application using Luduvo OAuth.",
redirect_uris=[
"http://localhost:3000/callback"
],
is_confidential=True
)
Listing OAuth Applications
List all OAuth applications belonging to the authenticated account.
from luduvo import Luduvo
client = Luduvo("YOUR_LUDUVO_TOKEN")
apps = client.oauth.list()
for app in apps:
print("Name:", app["name"])
print("Client ID:", app["client_id"])
print()
Deleting an OAuth Application
Delete an OAuth application using its client_id.
from luduvo import Luduvo
client = Luduvo("YOUR_LUDUVO_TOKEN")
client.oauth.delete(
"ldv_b748212bcc097120d2bfac589a6977dd"
)
The numeric application ID should not be used for deletion.
Use:
client_id
instead of:
id
PKCE
PKCE values can be generated with:
from luduvo import Luduvo
client = Luduvo()
pkce = client.oauth.create_pkce()
print("Code verifier:", pkce["code_verifier"])
print("Code challenge:", pkce["code_challenge"])
The returned object contains:
{
"code_verifier": "...",
"code_challenge": "..."
}
The library generates the challenge using SHA-256 and Base64 URL encoding.
The authorization request uses:
code_challenge_method=S256
The code_verifier must be kept until the authorization code is exchanged for an access token.
Authorization
Creating an Authorization URL
Generate a PKCE pair:
pkce = client.oauth.create_pkce()
Then create the authorization URL:
auth_url, state = client.oauth.authorize_url(
client_id="ldv_b748212bcc097120d2bfac589a6977dd",
redirect_uri="http://localhost:3000/callback",
code_challenge=pkce["code_challenge"]
)
print(auth_url)
print(state)
The generated authorization URL contains parameters such as:
response_type=code
client_id=...
redirect_uri=...
scope=identify
code_challenge=...
code_challenge_method=S256
state=...
The state value should be stored and verified when the OAuth callback is received.
Authorization URL Parameters
authorize_url() accepts:
client.oauth.authorize_url(
client_id,
redirect_uri,
code_challenge,
state=None,
scope="identify",
prompt=None
)
client_id
The OAuth application's client ID.
Example:
client_id="ldv_b748212bcc097120d2bfac589a6977dd"
redirect_uri
The callback URL registered with the OAuth application.
Example:
redirect_uri="http://localhost:3000/callback"
The URI must match one of the application's registered redirect URIs.
code_challenge
The PKCE challenge generated by:
pkce = client.oauth.create_pkce()
pkce["code_challenge"]
state
An optional state value.
If omitted, the library automatically generates a secure random state.
Example:
auth_url, state = client.oauth.authorize_url(
client_id="ldv_b748212bcc097120d2bfac589a6977dd",
redirect_uri="http://localhost:3000/callback",
code_challenge=pkce["code_challenge"]
)
scope
The OAuth scope.
The default scope is:
identify
Example:
auth_url, state = client.oauth.authorize_url(
client_id="ldv_b748212bcc097120d2bfac589a6977dd",
redirect_uri="http://localhost:3000/callback",
code_challenge=pkce["code_challenge"],
scope="identify"
)
prompt
An optional prompt value can be passed to the authorization endpoint.
auth_url, state = client.oauth.authorize_url(
client_id="ldv_b748212bcc097120d2bfac589a6977dd",
redirect_uri="http://localhost:3000/callback",
code_challenge=pkce["code_challenge"],
prompt="login"
)
Token Exchange
After the user authorizes the application, Luduvo redirects to the registered callback URL.
The callback contains an authorization code.
Exchange the code for an access token:
token = client.oauth.token(
client_id="ldv_b748212bcc097120d2bfac589a6977dd",
client_secret="YOUR_CLIENT_SECRET",
redirect_uri="http://localhost:3000/callback",
code="AUTHORIZATION_CODE",
code_verifier=pkce["code_verifier"]
)
print(token)
The token request sends:
{
"grant_type": "authorization_code",
"client_id": "...",
"client_secret": "...",
"redirect_uri": "...",
"code": "...",
"code_verifier": "..."
}
The authorization code can only be used according to the OAuth server's code expiration and reuse rules.
User Information
Once an OAuth access token has been received, user information can be requested using:
user = client.oauth.userinfo(
access_token=token["access_token"]
)
print(user)
A userinfo response looks similar to:
{
"avatar_url": "https://assets.luduvo.com/headshots/5/0197c88cd526d6a5f3d7ead056d1f12fba6df6a1b2dd9454fe022a978ab88970.png",
"created_at": 1774378965,
"display_name": "dargy",
"id": 5,
"sub": "5",
"username": "dargs"
}
The available fields include:
| Field | Description |
|---|---|
id |
Luduvo user ID |
sub |
OAuth subject identifier |
username |
Luduvo username |
display_name |
User display name |
avatar_url |
User avatar URL |
created_at |
Account creation timestamp |
Using the Access Token
The access token can be passed directly to userinfo():
user = client.oauth.userinfo(
access_token=token["access_token"]
)
Alternatively, assign the access token to the client:
client.token = token["access_token"]
Then:
user = client.oauth.userinfo()
This allows userinfo() to use the client's stored token.
Complete OAuth Example
The following example demonstrates the complete OAuth flow.
from luduvo import Luduvo
client = Luduvo("YOUR_LUDUVO_TOKEN")
# Generate PKCE values
pkce = client.oauth.create_pkce()
# Create the authorization URL
auth_url, state = client.oauth.authorize_url(
client_id="YOUR_CLIENT_ID",
redirect_uri="http://localhost:3000/callback",
code_challenge=pkce["code_challenge"]
)
print("Open this URL in your browser:")
print(auth_url)
# After the user authorizes the application,
# your callback receives the authorization code.
code = input("Authorization code: ")
# Exchange the authorization code for an access token
token = client.oauth.token(
client_id="YOUR_CLIENT_ID",
client_secret="YOUR_CLIENT_SECRET",
redirect_uri="http://localhost:3000/callback",
code=code,
code_verifier=pkce["code_verifier"]
)
print("Access token received.")
# Request user information
user = client.oauth.userinfo(
access_token=token["access_token"]
)
print("User ID:", user["id"])
print("Username:", user["username"])
print("Display Name:", user["display_name"])
Flask Callback Example
A minimal Flask application can be used to handle the OAuth callback.
from flask import Flask, redirect, request
from luduvo import Luduvo
app = Flask(__name__)
client = Luduvo("YOUR_LUDUVO_TOKEN")
pkce = client.oauth.create_pkce()
CLIENT_ID = "YOUR_CLIENT_ID"
CLIENT_SECRET = "YOUR_CLIENT_SECRET"
REDIRECT_URI = "http://127.0.0.1:3000/callback"
auth_url, state = client.oauth.authorize_url(
client_id=CLIENT_ID,
redirect_uri=REDIRECT_URI,
code_challenge=pkce["code_challenge"],
state=state
)
@app.route("/")
def index():
return f'<a href="{auth_url}">Login with Luduvo</a>'
@app.route("/callback")
def callback():
code = request.args.get("code")
returned_state = request.args.get("state")
if not code:
return "Missing authorization code.", 400
if returned_state != state:
return "Invalid state.", 400
token = client.oauth.token(
client_id=CLIENT_ID,
client_secret=CLIENT_SECRET,
redirect_uri=REDIRECT_URI,
code=code,
code_verifier=pkce["code_verifier"]
)
user = client.oauth.userinfo(
access_token=token["access_token"]
)
return {
"user": user,
"token": token
}
if __name__ == "__main__":
app.run(
host="127.0.0.1",
port=3000,
debug=True
)
For a real application, store the PKCE verifier and OAuth state in the user's server-side session rather than using global variables.
API Endpoints
The library currently uses these Luduvo OAuth endpoints:
| Method | Endpoint | Purpose |
|---|---|---|
POST |
/oauth/apps |
Create OAuth application |
GET |
/oauth/apps |
List OAuth applications |
DELETE |
/oauth/apps/{client_id} |
Delete OAuth application |
GET |
/oauth/authorize |
Authorize OAuth application |
POST |
/oauth/token |
Exchange authorization code |
GET |
/oauth/userinfo |
Get authenticated user |
The complete base URL is:
https://api.luduvo.com
Authentication
Application-management requests use a Luduvo API token:
Authorization: Bearer YOUR_LUDUVO_TOKEN
OAuth userinfo requests use an OAuth access token:
Authorization: Bearer YOUR_ACCESS_TOKEN
The library automatically sets the appropriate headers for requests made through the client.
Error Handling
API errors raise a RuntimeError.
Example:
from luduvo import Luduvo
client = Luduvo("YOUR_LUDUVO_TOKEN")
try:
apps = client.oauth.list()
except RuntimeError as error:
print(error)
An error contains the HTTP status code and the response returned by the API.
For example:
Luduvo API returned 401: {'error': 'unauthorized'}
Security
Never expose your Luduvo API token or OAuth client secret in frontend JavaScript, public repositories, or client-side applications.
Store secrets in environment variables or another secure secret store.
For example:
import os
from luduvo import Luduvo
client = Luduvo(
os.getenv("LUDUVO_TOKEN")
)
For OAuth applications, keep the following values private:
- API tokens
- OAuth client secrets
- OAuth access tokens
- PKCE code verifiers
The authorization state value should also be verified before accepting an OAuth callback.
Environment Variables
A common setup is:
LUDUVO_TOKEN=your_token_here
Python:
import os
from luduvo import Luduvo
client = Luduvo(
os.getenv("LUDUVO_TOKEN")
)
On Windows PowerShell:
$env:LUDUVO_TOKEN="YOUR_TOKEN_HERE"
Then run:
python main.py
Package Structure
The project structure is:
luduvo.py/
├── luduvo/
│ ├── __init__.py
│ └── client.py
├── demo/
│ └── test.py
├── pyproject.toml
└── README.md
The package is imported as:
import luduvo
or:
from luduvo import Luduvo
API Client
The main client class is:
from luduvo import Luduvo
client = Luduvo()
The client exposes OAuth functionality through:
client.oauth
Available OAuth methods:
client.oauth.create(...)
client.oauth.create_oauth(...)
client.oauth.delete(...)
client.oauth.list(...)
client.oauth.create_pkce(...)
client.oauth.authorize_url(...)
client.oauth.token(...)
client.oauth.userinfo(...)
Metadata
Release files for luduvo.py 0.1.13
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| luduvo_py-0.1.13.tar.gz | 6.7 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| luduvo_py-0.1.13-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 13.4 kB
Release files / luduvo_py-0.1.13.tar.gz
| Download URL | luduvo_py-0.1.13.tar.gz |
|---|---|
| Size | 6.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
4dd4532be2cdb902eb7cb5947fec34578098e4b29ca71deb26b8bae2965bda0d
|
|
BLAKE2b-256 checksum How to use checksums |
3b8cd7553a4b8590f423d48371160115e47349b549c3ede2e8488005c74f4150
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Release files / luduvo_py-0.1.13-py3-none-any.whl
| Download URL | luduvo_py-0.1.13-py3-none-any.whl |
|---|---|
| Size | 6.7 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
254064b0d67baaeef3cd66232144659d64c490865047308f73c9a07b6a93f0e4
|
|
BLAKE2b-256 checksum How to use checksums |
57391af1eee7d144602dfc6d3638c04945a10292186907f1047cb6137e392656
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|