Skip to main content

Bitcoin Cash OAuth - Django

Bitcoin Cash OAuth authentication for Django and Django REST Framework (DRF).

Installation

pip install bitcoincash-oauth-django

Add to INSTALLED_APPS:

INSTALLED_APPS = [
    ...
    'bitcoincash_oauth_django',
]

Django Views Usage

URL Configuration

# urls.py
from django.urls import path
from bitcoincash_oauth_django import register, token, refresh, revoke, me

urlpatterns = [
    path('auth/register', register, name='register'),
    path('auth/token', token, name='token'),
    path('auth/refresh', refresh, name='refresh'),
    path('auth/revoke', revoke, name='revoke'),
    path('auth/me', me, name='me'),
]

Custom View Instance

# urls.py
from django.urls import path
from bitcoincash_oauth_django import BitcoinCashOAuthViews

oauth = BitcoinCashOAuthViews(
    token_ttl=3600,
    refresh_token_ttl=2592000,
    max_tokens_per_user=5
)

urlpatterns = [
    path('auth/register', oauth.register_view, name='register'),
    path('auth/token', oauth.token_view, name='token'),
    path('auth/refresh', oauth.refresh_view, name='refresh'),
    path('auth/revoke', oauth.revoke_view, name='revoke'),
    path('auth/me', oauth.me_view, name='me'),
]

Django REST Framework Usage

URL Configuration

# urls.py
from django.urls import path
from bitcoincash_oauth_django.drf import (
    RegisterView, TokenView, RefreshView, RevokeView, MeView
)

urlpatterns = [
    path('auth/register', RegisterView.as_view(), name='register'),
    path('auth/token', TokenView.as_view(), name='token'),
    path('auth/refresh', RefreshView.as_view(), name='refresh'),
    path('auth/revoke', RevokeView.as_view(), name='revoke'),
    path('auth/me', MeView.as_view(), name='me'),
]

Protecting Views with DRF

from rest_framework.views import APIView
from rest_framework.response import Response
from bitcoincash_oauth_django.drf import IsBitcoinCashAuthenticated, HasScope

class ProtectedView(APIView):
    permission_classes = [IsBitcoinCashAuthenticated]
    
    def get(self, request):
        # Access token data from request
        user_id = request.token_data.user_id
        scopes = request.token_data.scopes
        
        return Response({
            "user_id": user_id,
            "scopes": scopes,
            "message": "This is a protected resource"
        })

class AdminView(APIView):
    permission_classes = [IsBitcoinCashAuthenticated, HasScope]
    required_scopes = ["admin"]
    
    def get(self, request):
        return Response({"message": "Admin only"})

Using with ViewSets

from rest_framework import viewsets
from rest_framework.decorators import action
from bitcoincash_oauth_django.drf import IsBitcoinCashAuthenticated

class MyViewSet(viewsets.ViewSet):
    permission_classes = [IsBitcoinCashAuthenticated]
    
    def list(self, request):
        user_id = request.token_data.user_id
        return Response({"user_id": user_id, "items": []})

API Endpoints

POST /auth/register

Register a new user with a Bitcoin Cash address. Signature verification is required to prove wallet ownership.

Request:

{
  "bitcoincash_address": "bitcoincash:qqrxvhnn88gmpczyxry254vcsnl6canmkqgt98lpn5",
  "user_id": "your_user_id",
  "timestamp": 1234567890,
  "domain": "app.example.com",
  "public_key": "0279BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798",
  "signature": "3045022100..."
}

Message Format: bitcoincash-oauth|domain|userId|timestamp|register

  • bitcoincash-oauth: Protocol identifier (prevents cross-protocol replay)
  • domain: Domain/host of the application (prevents phishing)
  • userId: User's unique identifier
  • timestamp: Unix timestamp for replay protection
  • register: Action identifier

Response:

{
  "user_id": "user_abc123",
  "address": "bitcoincash:qqrxvhnn88gmpczyxry254vcsnl6canmkqgt98lpn5",
  "message": "User registered successfully"
}

POST /auth/token

Obtain an OAuth token using Bitcoin Cash signature. The client must sign the message in the format bitcoincash-oauth|domain|userId|timestamp.

Request:

{
  "user_id": "user_abc123",
  "timestamp": 1234567890,
  "domain": "app.example.com",
  "public_key": "0279BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798",
  "signature": "3045022100...",
  "scopes": ["read", "write"]
}

Message Format: bitcoincash-oauth|domain|userId|timestamp

  • bitcoincash-oauth: Protocol identifier (prevents cross-protocol replay)
  • domain: Domain/host of the application (prevents phishing)
  • userId: User's unique identifier
  • timestamp: Unix timestamp for replay protection

Response:

{
  "access_token": "eyJhbGciOiJIUzI1NiIs...",
  "token_type": "bearer",
  "expires_in": 3600,
  "refresh_token": "dGhpcyBpcyBhIHJlZnJlc2g...",
  "scopes": ["read", "write"]
}

POST /auth/refresh

Refresh an access token.

Request:

{
  "refresh_token": "dGhpcyBpcyBhIHJlZnJlc2g..."
}

POST /auth/revoke

Revoke an access token.

Request:

{
  "token": "eyJhbGciOiJIUzI1NiIs..."
}

GET /auth/me

Get current user information (requires Bearer token).

Headers:

Authorization: Bearer eyJhbGciOiJIUzI1NiIs...

Advanced Usage

Using the Validator Directly

from bitcoincash_oauth_django import BitcoinCashValidator, verify_bitcoin_cash_auth

# Validate a CashAddr
is_valid, network = BitcoinCashValidator.validate_cash_address(
    "bitcoincash:qqrxvhnn88gmpczyxry254vcsnl6canmkqgt98lpn5"
)

# Verify authentication with domain binding
is_valid, reason = verify_bitcoin_cash_auth(
    user_id="user_123",
    timestamp=1234567890,
    public_key="0279BE...",
    signature="3045...",
    expected_address="bitcoincash:qz7f...",
    domain="app.example.com"  # Optional: prevents phishing across domains
)

# Convert public key to address
address = BitcoinCashValidator.public_key_to_cash_address(
    bytes.fromhex("0279BE..."),
    network="mainnet"
)

Custom Token Manager

from bitcoincash_oauth_django import TokenManager, token_manager

# Configure the singleton token manager
token_manager.access_token_ttl = 7200  # 2 hours
token_manager.max_tokens_per_user = 10

# Or create your own instance
custom_manager = TokenManager(
    access_token_ttl=7200,
    refresh_token_ttl=604800,  # 7 days
    max_tokens_per_user=10
)

DRF Permission Classes

Permission Class Description
IsBitcoinCashAuthenticated Validates Bearer token and attaches token_data to request
HasScope Checks if user has required OAuth scopes

Configuration

# settings.py

# Optional: Configure token settings
BITCOINCASH_OAUTH = {
    'TOKEN_TTL': 3600,  # 1 hour
    'REFRESH_TOKEN_TTL': 2592000,  # 30 days
    'MAX_TOKENS_PER_USER': 5,
}
Setting Default Description
TOKEN_TTL 3600 Access token lifetime (seconds)
REFRESH_TOKEN_TTL 2592000 Refresh token lifetime (seconds)
MAX_TOKENS_PER_USER 5 Maximum active tokens per user
MAX_TIMESTAMP_DIFF 300 Max timestamp age for replay protection (seconds)

Custom Models (Avoiding Conflicts)

If your project already has models named BitcoinCashUser or OAuthToken, you can use custom models:

# settings.py

BITCOINCASH_OAUTH = {
    'USER_MODEL': 'myapp.MyBitcoinCashUser',  # Your custom user model
    'TOKEN_MODEL': 'myapp.MyOAuthToken',      # Your custom token model
}

Your custom models should inherit from the base models:

# myapp/models.py
from bitcoincash_oauth_django.models import BitcoinCashUser, OAuthToken

class MyBitcoinCashUser(BitcoinCashUser):
    # Add your custom fields
    custom_field = models.CharField(max_length=100)

class MyOAuthToken(OAuthToken):
    # Add your custom fields
    custom_data = models.JSONField(default=dict)

Note: When using custom models, do NOT add bitcoincash_oauth_django to INSTALLED_APPS. Instead:

# settings.py
INSTALLED_APPS = [
    # 'bitcoincash_oauth_django',  # Don't add this
    'myapp',  # Add your app with the custom models
]

# Keep the URLs
urlpatterns = [
    path('auth/', include('bitcoincash_oauth_django.urls')),
]

Dependencies

  • django>=4.0
  • djangorestframework>=3.14.0
  • coincurve>=18.0.0
  • cashaddress>=1.0.6
  • PyJWT>=2.8.0

License

MIT

Metadata

Release files for bitcoincash-oauth-django 0.2.11

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for bitcoincash-oauth-django 0.2.11
File Size Uploaded Provenance Actions
bitcoincash_oauth_django-0.2.11.tar.gz 31.4 kB Without provenance Details for bitcoincash_oauth_django-0.2.11.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for bitcoincash-oauth-django 0.2.11
File Interpreter ABI Platform Actions
bitcoincash_oauth_django-0.2.11-py3-none-any.whl Python 3 none any Details for bitcoincash_oauth_django-0.2.11-py3-none-any.whl

Total release size: 75.9 kB

Release files / bitcoincash_oauth_django-0.2.11.tar.gz

Download URL bitcoincash_oauth_django-0.2.11.tar.gz
Size 31.4 kB
Tags Source
SHA-256 checksum
How to use checksums
8d64764883c2110d192d926439b23e0b864d80957267744b8e1592153e93b2f3
BLAKE2b-256 checksum
How to use checksums
80c68fa1cd1522e500b7d4d20feee2cf6787a802484c15c0c52bb50953d48233
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.11.8

Release files / bitcoincash_oauth_django-0.2.11-py3-none-any.whl

Download URL bitcoincash_oauth_django-0.2.11-py3-none-any.whl
Size 44.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
3a83c761d855898e2eee3354414a1d124f3a90a8213f238240e2998e5d6eda93
BLAKE2b-256 checksum
How to use checksums
414df65f0f748b508aebfcac8332b05ea7c9bb35886e37ee4627e3ce8ffd8a44
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.11.8

Security for bitcoincash-oauth-django 0.2.11

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page