A simple, secure, and universal JWT library for web and mobile applications
Project description
SCG JWT Token for Python
A simple, secure, and universal JWT library for web and mobile applications.
Installation
pip install scg-jwt-token
Quick Start
from scg_jwt_token import SCGJwtToken
# Create JWT instance
jwt = SCGJwtToken("your-secret-key")
# Create token
token = jwt.sign({
"user_id": 123,
"email": "user@example.com",
"role": "user"
})
# Verify token
try:
payload = jwt.verify(token)
print(f"User: {payload['email']}")
except ValueError as e:
print(f"Invalid token: {e}")
Features
- Stateless: No database storage needed for tokens
- Secure: Uses HMAC SHA-256 with proper JWT standards
- Universal: Works with web apps, mobile apps, APIs, and microservices
- Zero Dependencies: Pure Python implementation
- Type Hints: Full TypeScript-style type annotations
- Production Ready: Comprehensive error handling and validation
API Reference
SCGJwtToken
Constructor
jwt = SCGJwtToken(secret_key)
Methods
sign(payload, expires_in=3600, issuer=None, audience=None)
Create a JWT token.
token = jwt.sign(
{"user_id": 123, "role": "admin"},
expires_in=86400, # 24 hours
issuer="my-app",
audience="app-users"
)
verify(token, issuer=None, audience=None)
Verify and decode a token.
payload = jwt.verify(token)
decode(token)
Decode without verification (for debugging).
decoded = jwt.decode(token)
print(decoded['header'])
print(decoded['payload'])
is_expired(token)
Check if token is expired.
if jwt.is_expired(token):
print("Token expired")
refresh(token, expires_in=3600)
Create new token with updated expiration.
new_token = jwt.refresh(old_token, expires_in=86400)
get_stats()
Get performance statistics.
stats = jwt.get_stats()
print(f"Tokens created: {stats['tokens_created']}")
Quick Operations
from scg_jwt_token import QuickJWT
# Quick sign with auto-generated secret
result = QuickJWT.quick_sign({"user_id": 123})
print(f"Token: {result['token']}")
print(f"Secret: {result['secret']}")
# Quick verify
payload = QuickJWT.quick_verify(token, secret)
Web Framework Examples
Flask
from flask import Flask, request, jsonify
from scg_jwt_token import SCGJwtToken
import os
app = Flask(__name__)
jwt = SCGJwtToken(os.getenv('JWT_SECRET'))
@app.route('/api/login', methods=['POST'])
def login():
# Validate user credentials here
user = validate_user(request.json['email'], request.json['password'])
if user:
token = jwt.sign({
'user_id': user['id'],
'email': user['email'],
'role': user['role']
}, expires_in=86400)
return jsonify({'token': token, 'user': user})
return jsonify({'error': 'Invalid credentials'}), 401
@app.route('/api/protected', methods=['GET'])
def protected():
auth_header = request.headers.get('Authorization')
if not auth_header or not auth_header.startswith('Bearer '):
return jsonify({'error': 'Token required'}), 401
token = auth_header.split(' ')[1]
try:
user = jwt.verify(token)
return jsonify({'message': 'Access granted', 'user': user})
except ValueError:
return jsonify({'error': 'Invalid token'}), 403
Django
from django.http import JsonResponse
from django.views.decorators.csrf import csrf_exempt
from scg_jwt_token import SCGJwtToken
import json
import os
jwt = SCGJwtToken(os.getenv('JWT_SECRET'))
@csrf_exempt
def login_view(request):
if request.method == 'POST':
data = json.loads(request.body)
user = authenticate_user(data['email'], data['password'])
if user:
token = jwt.sign({
'user_id': user.id,
'email': user.email,
'role': user.role
})
return JsonResponse({'token': token})
return JsonResponse({'error': 'Invalid credentials'}, status=401)
def protected_view(request):
auth_header = request.META.get('HTTP_AUTHORIZATION')
if not auth_header or not auth_header.startswith('Bearer '):
return JsonResponse({'error': 'Token required'}, status=401)
token = auth_header.split(' ')[1]
try:
user = jwt.verify(token)
return JsonResponse({'user': user})
except ValueError:
return JsonResponse({'error': 'Invalid token'}, status=403)
FastAPI
from fastapi import FastAPI, HTTPException, Depends, Header
from scg_jwt_token import SCGJwtToken
import os
app = FastAPI()
jwt = SCGJwtToken(os.getenv('JWT_SECRET'))
async def verify_token(authorization: str = Header(None)):
if not authorization or not authorization.startswith('Bearer '):
raise HTTPException(status_code=401, detail='Token required')
token = authorization.split(' ')[1]
try:
return jwt.verify(token)
except ValueError:
raise HTTPException(status_code=403, detail='Invalid token')
@app.post('/api/login')
async def login(credentials: dict):
user = await authenticate_user(credentials['email'], credentials['password'])
if user:
token = jwt.sign({
'user_id': user['id'],
'email': user['email'],
'role': user['role']
})
return {'token': token}
raise HTTPException(status_code=401, detail='Invalid credentials')
@app.get('/api/protected')
async def protected(user: dict = Depends(verify_token)):
return {'user': user}
Why JWT Over Sessions
Traditional Session-Based Auth
- User Login → Create Session → Store in Database → Return Session ID
- User Request → Database Lookup → Validate Session → Process Request
- Every request = Database query = Slow & Resource Heavy
SCG JWT Token-Based Auth
- User Login → Create JWT Token → Return Token (NO database storage)
- User Request → Verify JWT Signature → Process Request
- No database queries = Lightning Fast & Highly Scalable
Security Best Practices
-
Use environment variables for secrets:
jwt = SCGJwtToken(os.getenv('JWT_SECRET'))
-
Set reasonable expiration times:
token = jwt.sign(payload, expires_in=86400) # 24 hours
-
Always use HTTPS in production
-
Validate tokens on server side:
try: payload = jwt.verify(token) except ValueError as e: return error_response('Invalid token')
-
Use proper Authorization headers:
Authorization: Bearer <your-jwt-token>
Testing
import unittest
from scg_jwt_token import SCGJwtToken
class TestSCGJwt(unittest.TestCase):
def setUp(self):
self.jwt = SCGJwtToken("test-secret")
def test_create_and_verify_token(self):
payload = {"user_id": 123, "role": "admin"}
token = self.jwt.sign(payload)
decoded = self.jwt.verify(token)
self.assertEqual(decoded['user_id'], 123)
self.assertEqual(decoded['role'], "admin")
def test_expired_token(self):
token = self.jwt.sign({"user_id": 123}, expires_in=-1)
with self.assertRaises(ValueError):
self.jwt.verify(token)
if __name__ == '__main__':
unittest.main()
Use Cases
Perfect for:
- Web Applications: Flask, Django, FastAPI applications
- Mobile APIs: REST APIs for mobile apps
- Microservices: Service-to-service authentication
- Single Page Apps: React, Vue, Angular frontends
- Cross-platform: Same authentication across all platforms
Requirements
- Python 3.7+
- No external dependencies
License
MIT License
Support
- GitHub Repository
- Report Issues
- Email: hemantthapa1998@gmail.com
- Business: contact@squidconsultancy.com
Built by Analytics With Harry and Squid Consultancy Group Limited.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file scg_jwt_token-2.0.0.tar.gz.
File metadata
- Download URL: scg_jwt_token-2.0.0.tar.gz
- Upload date:
- Size: 8.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.10.11
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9cf638e48ebee32b72a74a21aae13169a3732cf83583b4ea997a4ea237d75815
|
|
| MD5 |
5a1518030c4c82769ea6ae49a1b4e619
|
|
| BLAKE2b-256 |
37870f62a5704474e68b50008670a13b2b23e6192e68d7995282b238104bdb70
|
File details
Details for the file scg_jwt_token-2.0.0-py3-none-any.whl.
File metadata
- Download URL: scg_jwt_token-2.0.0-py3-none-any.whl
- Upload date:
- Size: 8.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.10.11
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3065c787ed5c3406d54e97635376a2734e6752ded6e3a7963541c4f68e2e4ba2
|
|
| MD5 |
5afb21f9e81701a5532fe5edd92ee38e
|
|
| BLAKE2b-256 |
cbd6b2cf747219e523be97b6198a90ef0eb211dcc8f7d0a33704567b12da1cbc
|