How to Integrate App Authentication with an OCPP Central System
As EV charging infrastructure grows, user-friendly mobile apps and dashboards are essential. But how do you securely authenticate users in your app and link their actions to OCPP-connected chargers?
In this guide, we’ll show you how to build an app authentication system that works hand-in-hand with your OCPP central system (CSMS).
🧩 Architecture Overview
Components:
- Mobile App / Dashboard – Where users sign in and control charging
- Central System API (Flask) – REST API layer for users and admin actions
- OCPP WebSocket Server – Communicates with EVSEs via OCPP 1.6
- MongoDB – Stores users and charge point data
📊 Sequence Diagram: Start Charging via App
sequenceDiagram
participant User as Mobile App
participant API as Flask API Server
participant CSMS as OCPP Central System
participant EVSE as Charger (EVSE)
User->>API: POST /api/login (username, password)
API-->>User: JWT token + idTag
User->>API: POST /api/start_charging (evse_id, connector_id, token)
API->>CSMS: RemoteStartTransaction(idTag, connectorId)
CSMS->>EVSE: RemoteStartTransaction.req
EVSE-->>CSMS: RemoteStartTransaction.conf
CSMS-->>API: status = Accepted
API-->>User: {"status": "Accepted"}
This flow ensures only authenticated users can trigger OCPP commands like RemoteStartTransaction
.
🔑 1. User Authentication via JWT
We use Flask-JWT-Extended
to handle token-based auth.
Setup
Install:
pip install flask flask-jwt-extended pymongo werkzeug
Flask routes for signup and login:
@flask_app.route("/api/signup", methods=["POST"])
def signup():
...
token = create_access_token(identity=user["username"])
return jsonify(access_token=token, idTag=user["idTag"])
@flask_app.route("/api/login", methods=["POST"])
def login():
...
token = create_access_token(identity=user["username"])
return jsonify(access_token=token, idTag=user["idTag"])
⚡ 2. Secure OCPP Action (Remote Start)
@flask_app.route("/api/start_charging", methods=["POST"])
@jwt_required()
def start_charging():
cp = connected_charge_points.get(evse_id)
payload = call.RemoteStartTransactionPayload(id_tag=id_tag, connector_id=connector_id)
future = asyncio.run_coroutine_threadsafe(cp.call(payload), main_loop)
result = future.result(timeout=10)
return jsonify({"status": result.status})
🧠 Best Practices
- Hash passwords with
werkzeug.security
- Use JWTs and set expiration
- Use
idTag
consistently across auth + OCPP - Restrict access by
role
(user/admin/root) - Link
idTag
to vehicles or accounts
🔧 Tools Used
Tool | Purpose |
---|---|
Flask | REST API backend |
Flask-JWT | Auth token generation |
PyMongo | MongoDB access |
asyncio | Concurrency + WebSocket calls |
OCPP v1.6 | Communication with EVSEs |
🚀 Going Further
- Add QR-based pairing:
ocpp://CP001?connector=1
- Add firmware update + diagnostics features
- Build admin dashboard with user role control
Want the full source code or Postman test collection? Just ask!
Related Posts
- Understanding Wazuh by Exploring the Open Source Projects Behind It
- Beginner’s Guide: How EV Charging Apps Communicate, Track Charging, and Calculate Costs
- Building an OCPP 1.6 Central System with Flask async, WebSockets, and MongoDB
- How AI Supercharges Accounting and Inventory in Odoo (with Dev Insights)
- Building a Fullstack E-commerce System with JavaScript
- Building Agentic AI with Python, Langchain, and Ollama for eCommerce & Factory Automation
- Diagnosing the Root Cause of P0420 with Python, OBD-II, and Live Sensor Data
- How to Apply The Mom Test to Validate Your Startup Idea the Right Way
- When to Choose Rasa vs Langchain for Building Chatbots
- Introducing OCR Document Manager: Extract Text from Documents with Ease
- Testing an AI Tool That Finds Winning Products Before They Trend — Interested?
- Your Website Is Losing Leads After Hours — Here’s the Fix
- How Agentic AI is Revolutionizing Smart Farming — And Why Your Farm Needs It Now
- How to Apply RAG Chatbot with LangChain + Ollama
- Automating EXFO Instruments with SCPI: A Practical Guide
- Design Patterns That Help Tame Legacy Code (With Python Examples)
- How to Safely Add New Features to Legacy Code — A Developer’s Guide
- Modernizing Legacy Software — Without Breaking Everything
- How OpenSearch Works — Architecture, Internals & Real-Time Search Explained
- Choosing the Right Strategy for Basic vs Premium Features in Django
Our Products
Related Posts
- Understanding Wazuh by Exploring the Open Source Projects Behind It
- Beginner’s Guide: How EV Charging Apps Communicate, Track Charging, and Calculate Costs
- Building an OCPP 1.6 Central System with Flask async, WebSockets, and MongoDB
- How AI Supercharges Accounting and Inventory in Odoo (with Dev Insights)
- Building a Fullstack E-commerce System with JavaScript
- Building Agentic AI with Python, Langchain, and Ollama for eCommerce & Factory Automation
- Diagnosing the Root Cause of P0420 with Python, OBD-II, and Live Sensor Data
- How to Apply The Mom Test to Validate Your Startup Idea the Right Way
- When to Choose Rasa vs Langchain for Building Chatbots
- Introducing OCR Document Manager: Extract Text from Documents with Ease
- Testing an AI Tool That Finds Winning Products Before They Trend — Interested?
- Your Website Is Losing Leads After Hours — Here’s the Fix
- How Agentic AI is Revolutionizing Smart Farming — And Why Your Farm Needs It Now
- How to Apply RAG Chatbot with LangChain + Ollama
- Automating EXFO Instruments with SCPI: A Practical Guide
- Design Patterns That Help Tame Legacy Code (With Python Examples)
- How to Safely Add New Features to Legacy Code — A Developer’s Guide
- Modernizing Legacy Software — Without Breaking Everything
- How OpenSearch Works — Architecture, Internals & Real-Time Search Explained
- Choosing the Right Strategy for Basic vs Premium Features in Django