Files
ORCID2SWORD/README.md
T
Mireya Cueto Garrido bf35fcaaf3 Revise README with project overview and tech stack
Updated project description, added tech stack badges, and detailed project overview.
2026-05-08 13:41:49 +02:00

11 KiB

ORCID SWORD System

FastAPI Python React Vite PostgreSQL Redis Docker ORCID OAuth

Full-stack platform for ORCID authentication, researcher synchronization, and publication export in SWORD XML / ZIP formats.

certificate. Overview: What is this project meant

orcid-system is designed for research workflows where ORCID data must be ingested, normalized, and exported.

Core capabilities:

  • ORCID OAuth 3-legged login
  • researcher search and synchronization against ORCID
  • publication export by selection or by researcher
  • export formats: SWORD XML and ZIP
  • dual access model: user JWT or service API key (for export)

Note

The stack is local-first with Docker, but includes production-oriented hardening (CORS policy, trusted hosts, security headers, rate limiting, etc.).


certificate. Tech Stack

Backend

  • FastAPI
  • SQLAlchemy
  • PostgreSQL
  • Redis
  • python-jose (JWT)
  • slowapi (rate limit)
  • APScheduler
  • httpx

Frontend

  • React 19
  • Vite 8
  • React Router
  • TailwindCSS 4
  • Sonner (notifications)

Infrastructure

  • Docker / Docker Compose

certificate. Quick Start

From the project root:

docker compose down
docker compose up --build

Default local URLs:

  • Frontend: http://localhost:5173
  • Backend: http://localhost:8000

Important

Current compose mapping uses loopback binding:

  • 127.0.0.1:5173:5173
  • 127.0.0.1:8000:8000
    This means services are reachable from the host machine, not exposed publicly by default.

certificate. Environment Configuration

Backend:

  • Main file: backend/.env
  • Reference: backend/.env.example

Frontend:

  • Compose/dev file: frontend/.env
  • Optional local override for host dev: frontend/.env.local

Important backend variables:

  • ORCID_CLIENT_ID
  • ORCID_CLIENT_SECRET
  • ORCID_REDIRECT_URI
  • JWT_SECRET
  • API_KEY_NAME
  • API_KEY_VALUE
  • CORS_ALLOWED_ORIGINS
  • TRUSTED_HOSTS
  • DATABASE_URL
  • REDIS_URL

Important frontend variables:

  • VITE_API_URL (empty in Docker setup, so Vite proxy handles /api)
  • VITE_API_PROXY_TARGET (defaults to http://backend:8000 in compose network)
  • VITE_API_KEY (must match backend API_KEY_VALUE when using API key mode)
  • VITE_USE_MOCKS
  • VITE_ORCID_PUBLIC_API_BASE (optional override)

Warning

Never commit real production secrets. Rotate JWT_SECRET, API_KEY_VALUE, and ORCID_CLIENT_SECRET before deployment.


certificate. ngrok Bridge for Local OAuth Callback

To test OAuth callback from ORCID in local environments, compose can inject a public callback URL:

environment:
  ORCID_REDIRECT_URI: https://jargon-supreme-palpable.ngrok-free.dev/callback

Note

Values under docker-compose.yml -> services.backend.environment override backend/.env inside the container.


certificate. API Endpoints

Base backend URL: http://localhost:8000

Module Method Endpoint Auth Parameters Body Notes
Health GET /health None None None Liveness check
ORCID Auth GET /api/auth/orcid/authorize None None None Redirects to ORCID
ORCID Auth GET /api/auth/orcid/callback None code, state None Exchanges OAuth code for backend JWT
ORCID Auth GET /callback None code, state None Alias for callback flow
Researchers POST /api/researchers/search Optional Bearer None {"orcid_ids":[...]} Batch search/sync
Researchers POST /api/researchers/{orcid_id}/sync Optional Bearer orcid_id None Full sync of one researcher
Export SWORD POST /api/export/sword/publications Bearer or API key None ["publication_uuid", ...] Export selected publications
Export SWORD GET /api/export/sword/researcher/{orcid_id} Bearer or API key orcid_id None Export all by researcher
Export ZIP POST /api/export/zip/publications Bearer or API key None ["publication_uuid", ...] Export selected publications
Export ZIP GET /api/export/zip/researcher/{orcid_id} Bearer or API key orcid_id None Export all by researcher

Important

.../publications endpoints require publication IDs, not researcher.id.


certificate. Request Examples

Health

curl http://localhost:8000/health

Search one or more researchers

curl -X POST "http://localhost:8000/api/researchers/search" \
  -H "Content-Type: application/json" \
  -d "{\"orcid_ids\":[\"0009-0000-0793-5376\"]}"

Sync one researcher

curl -X POST "http://localhost:8000/api/researchers/0009-0000-0793-5376/sync"

Export SWORD by researcher (API key mode)

curl "http://localhost:8000/api/export/sword/researcher/0009-0000-0793-5376" \
  -H "X-API-Key: YOUR_API_KEY" \
  -o sword.xml

Export ZIP by publication IDs (Bearer mode)

curl -X POST "http://localhost:8000/api/export/zip/publications" \
  -H "Authorization: Bearer YOUR_JWT" \
  -H "Content-Type: application/json" \
  -d "[\"04f6a2a6-b753-4432-982b-b88160f627fe\"]" \
  -o export.zip

certificate. Security Controls

Implemented controls in backend:

  • strict CORS allowlist
  • trusted host filtering
  • request body size limit
  • OAuth state validation
  • JWT validation with issuer/audience claims
  • API key validation via constant-time comparison
  • rate limiting
  • security headers middleware
  • non-root container and reduced privileges

Warning

For production, enforce HTTPS behind a reverse proxy and set concrete values for CORS_ALLOWED_ORIGINS and TRUSTED_HOSTS.


certificate. Frontend Details

The frontend is a React SPA using route-based navigation and a centralized API client.

Frontend routing

  • / → landing page
  • /dashboard/:orcid → researcher dashboard
  • /group → multi-researcher results
  • /callback → OAuth callback handler

Frontend API behavior (frontend/src/services/api.js)

  • central HTTP wrapper with ApiError
  • includes X-API-Key on requests when configured
  • includes Authorization: Bearer <token> when token exists in localStorage
  • supports mock mode through VITE_USE_MOCKS
  • supports Vite proxy mode when VITE_API_URL is empty

Vite proxy (frontend/vite.config.js)

  • /api proxied to VITE_API_PROXY_TARGET (http://backend:8000 in compose)
  • /health proxied to same target
  • dev host settings allow tunnel scenarios (ngrok callback testing)

certificate. Project Structure

orcid-system/
├── backend/
│   ├── app/
│   │   ├── api/
│   │   │   ├── auth.py
│   │   │   ├── researchers.py
│   │   │   └── export.py
│   │   ├── core/
│   │   │   ├── config.py
│   │   │   ├── rate_limit.py
│   │   │   ├── security_headers.py
│   │   │   ├── error_handlers.py
│   │   │   └── body_size.py
│   │   ├── db/
│   │   │   ├── models.py
│   │   │   ├── session.py
│   │   │   └── repositories/
│   │   ├── security/
│   │   │   ├── jwt.py
│   │   │   ├── api_key.py
│   │   │   └── oauth_state.py
│   │   ├── services/
│   │   │   ├── orcid_client.py
│   │   │   ├── sword_generator.py
│   │   │   ├── zip_generator.py
│   │   │   └── sync_service.py
│   │   ├── utils/
│   │   └── main.py
│   ├── .env
│   ├── .env.example
│   ├── .env.production
│   ├── Dockerfile
│   └── requirements.txt
├── frontend/
│   ├── src/
│   │   ├── components/
│   │   │   ├── dashboard/
│   │   │   ├── layout/
│   │   │   └── ui/
│   │   ├── contexts/
│   │   │   └── AuthContext.jsx
│   │   ├── pages/
│   │   │   ├── LandingPage.jsx
│   │   │   ├── DashboardPage.jsx
│   │   │   ├── GroupResultsPage.jsx
│   │   │   └── AuthCallbackPage.jsx
│   │   ├── services/
│   │   │   ├── api.js
│   │   │   └── mocks.js
│   │   ├── utils/
│   │   ├── App.jsx
│   │   └── main.jsx
│   ├── .env
│   ├── package.json
│   ├── vite.config.js
│   └── eslint.config.js
├── docker-compose.yml
└── README.md

certificate. Production Checklist

  • ENVIRONMENT=production
  • DEBUG=false
  • rotate all secrets
  • define strict CORS_ALLOWED_ORIGINS
  • define strict TRUSTED_HOSTS
  • enforce HTTPS via reverse proxy
  • keep DB/Redis private
  • configure monitoring and backups

github. Authors and Team

This project is the result of the collaboration with the University of Jaén.

Role Developer GitHub
Frontend Alexis López Moral @AlexisLopez-Dev
Backend Mireya Cueto Garrido @MireyaCueto

Direction

  • Proyect Supervisor: Luis Martínez López

Built with professional care and ❤️ for secure research data workflows at the University of Jaén.