Certo is a comprehensive digital credentials platform for issuing, managing, and verifying badges and certificates based on the Open Badges 3.0 specification and the W3C Verifiable Credentials data model.
Overview
Certo is an open-source platform that enables organizations and individuals to issue verifiable digital credentials (badges and certificates) following global standards. Whether you're running educational programs, workshops, certification courses, or need to recognize achievements, Certo provides a complete solution for creating, issuing, and verifying digital credentials.
How It Works
- Issuers create badge templates (Achievements) defining what the badge represents, criteria for earning it, and associated skills
- Issuers issue credentials to recipients either individually or in bulk via CSV upload
- Recipients receive their credentials and can view them in their dashboard
- Anyone can verify the authenticity of a credential using the public verification page
- Recipients can share their verified credentials on LinkedIn and other platforms
Standards Compliance
Certo implements:
- Open Badges 3.0: IMS Global Learning Consortium standard for digital credentials
- W3C Verifiable Credentials: Cryptographically secure and tamper-evident credentials
- Decentralized Identifiers: For robust identity management
Use Cases
- Educational Institutions: Issue course completion certificates and academic achievements
- Training Organizations: Provide verifiable certificates for workshops and training programs
- Event Organizers: Award attendance or participation badges for conferences and meetups
- Companies: Recognize employee skills, certifications, and professional development
- Open Source Communities: Acknowledge contributions and participation
- Professional Associations: Issue membership credentials and professional certifications
Features
π Badge & Certificate Management
- Create Achievements: Design badge templates with customizable criteria, skills, and metadata
- Issue Credentials: Issue digital certificates for workshops, courses, events, and projects
- Batch Issuance: Upload CSV files to issue credentials to multiple recipients simultaneously
- Role-Based Access: Separate issuer and recipient roles with appropriate permissions
π Verification & Security
- Cryptographic Verification: Verify badge authenticity using cryptographic proofs and the Verifiable Credentials model
- Revocation Support: Maintain revocation lists for invalidated credentials
- Tamper-Evident: All credentials are cryptographically signed and tamper-evident
π€ Sharing & Integration
- LinkedIn Integration: Share certificates directly on LinkedIn
- Multiple Export Formats: Export credentials in various formats
- Public Verification: Anyone can verify credential authenticity via the verification page
π Additional Features
- Evidence Attachments: Attach supporting evidence and narratives to credentials
- Endorsements: Third-party endorsement support for credentials
- Dashboard: View and manage all issued and received credentials
- Open Standards: Full compliance with Open Badges 3.0 specification
Project Structure
certo/
βββ src/
β βββ backend/ # Strapi 5.x backend (TypeScript)
β β βββ src/
β β β βββ api/ # API endpoints
β β β β βββ achievement/ # Badge templates/definitions (Open Badges 3.0)
β β β β βββ credential/ # Issued credentials/badges
β β β β βββ profile/ # User profiles (issuers & recipients)
β β β β βββ evidence/ # Evidence attachments
β β β β βββ endorsement/ # Third-party endorsements
β β β β βββ revocation-list/# Credential revocation lists
β β β βββ admin/ # Strapi admin customizations
β β β βββ components/ # Reusable content components
β β β βββ middlewares/ # Custom middlewares
β β β βββ utils/ # Utility functions
β β βββ config/ # Strapi configuration
β β βββ database/ # Database migrations
β β βββ public/ # Static files & uploads
β β βββ scripts/ # Utility scripts
β β βββ types/ # TypeScript type definitions
β β βββ Dockerfile # Backend Docker configuration
β β βββ package.json # Backend dependencies
β β
β βββ frontend/ # Nuxt 3 frontend (Vue 3 + TypeScript + Una UI)
β βββ pages/ # Application pages
β β βββ index.vue # Home page
β β βββ issue.vue # Badge issuance (CSV upload support)
β β βββ verify.vue # Credential verification
β β βββ dashboard.vue # User dashboard
β β βββ ... # Other pages
β βββ components/ # Vue components
β βββ composables/ # Vue composables
β βββ stores/ # Pinia state management
β βββ middleware/ # Route middleware (auth, etc.)
β βββ api/ # API client libraries
β βββ types/ # TypeScript types
β βββ plugins/ # Nuxt plugins
β βββ assets/ # CSS, images, SVG components
β βββ public/ # Static public files
β βββ e2e/ # Playwright E2E tests
β βββ Dockerfile # Frontend Docker configuration
β βββ package.json # Frontend dependencies
β
βββ netlify/ # Netlify serverless functions
β βββ functions/
β βββ og-credential/ # Open Graph image generation
βββ docker-compose.yml # Docker Compose configuration
βββ README.md # This file
βββ LICENSE # AGPL-3.0 License
βββ CONTRIBUTING.md # Contribution guidelines
βββ CODE_OF_CONDUCT.md # Code of conduct
Requirements
For Docker Setup (Recommended)
- Docker and Docker Compose
- Node.js 18-22.x (for local development)
For Local Development
- Node.js 18.x - 22.x
- npm 6.0.0 or higher
- PostgreSQL 13+ (or use SQLite for development)
Technology Stack
- Backend: Strapi 5.15.0, TypeScript 5.x, Node.js 18-22.x
- Frontend: Nuxt 3.10+, Vue 3.4+, TypeScript 5.x, Una UI
- Database: PostgreSQL (production) or SQLite (development)
- Authentication: JWT with jose library
- Testing: Vitest (unit), Playwright (E2E)
Development Setup
- Clone the repository:
git clone https://github.com/schrodinger-hat/certo.git
cd certo- Create environment variables:
Create a .env file in the src/backend directory with the following variables:
# Required Strapi Secrets ADMIN_JWT_SECRET=your-admin-jwt-secret JWT_SECRET=your-jwt-secret APP_KEYS=your-app-keys # Database Configuration (PostgreSQL) DATABASE_CLIENT=postgres DATABASE_HOST=localhost DATABASE_PORT=5432 DATABASE_NAME=certo DATABASE_USERNAME=strapi DATABASE_PASSWORD=strapi # Server Configuration HOST=0.0.0.0 PORT=1337 # Frontend URL (for CORS) FRONTEND_URL=http://localhost:3000
Create a .env file in the src/frontend directory:
# API Configuration NUXT_PUBLIC_API_URL=http://localhost:1337 NUXT_PUBLIC_WEBSITE_URL=http://localhost:3000 # Optional: Google Analytics NUXT_PUBLIC_GTAG=your-gtag-id
- Start the Docker containers:
This will start the backend (Strapi), frontend (Nuxt 3), and PostgreSQL database.
- Wait for the containers to initialize. On first run, the backend will automatically:
- Create sample data for testing
- Configure all necessary API permissions
Default login credentials (same for admin panel and frontend):
- Email:
admin@certo.com - Password:
certo
Sample data includes:
- A Strapi admin user (for the admin panel at
/admin) - An API user (for frontend authentication)
- A profile (configured as both Issuer and Recipient)
- A sample achievement ("Welcome to Certo")
- A sample credential/badge awarded to the admin user
Permissions automatically configured:
- Authenticated users can access all API endpoints (profiles, achievements, credentials, etc.)
- Public users can read and verify badges
Note: Seed data is only created on the first run. If you need to reset the database, run
docker-compose down -vto remove volumes, then start again.
- Access the applications:
- Backend (Strapi Admin): http://localhost:1337/admin
- Frontend (Nuxt 3): http://localhost:3000
Running Locally (Without Docker)
If you prefer to run the applications locally without Docker, you'll need to set up PostgreSQL separately or use SQLite for development.
Backend (Strapi)
- Set up your database (PostgreSQL or SQLite)
- Create the
.envfile as described above - Install and run:
cd src/backend npm install npm run develop # Development mode with auto-reload # or npm run dev # Alternative dev command
The Strapi admin panel will be available at http://localhost:1337/admin
First-time setup: Create an admin account when prompted on first launch.
Frontend (Nuxt 3)
- Create the
.envfile as described above - Install and run:
cd src/frontend
npm install
npm run devThe frontend will be available at http://localhost:3000
Development Workflow
- Start the backend first (it runs on port 1337)
- Start the frontend (it connects to the backend API)
- Create an admin account in Strapi
- Register a user account in the frontend
- Set user role to "issuer" in Strapi admin to issue badges
API Documentation
The API follows the Open Badges 3.0 specification. Swagger UI (OpenAPI) is available at http://localhost:1337/documentation.
Key Endpoints
Public Endpoints:
GET /api/credentials/:id- Retrieve public credential data (Open Badges 3.0 format)POST /api/credentials/verify- Verify credential authenticityGET /api/revocation-list/check/:id- Check if a credential is revoked
Authenticated Endpoints:
POST /api/achievements- Create badge templates (issuer only)POST /api/credentials/batch-issue- Issue credentials to multiple recipientsGET /api/profiles/me- Get current user profileGET /api/profiles/:id/credentials- Get user's credentialsPOST /api/endorsements- Create credential endorsementsPOST /api/evidence- Attach evidence to credentials
Data Models
- Achievement: Badge template/definition (Badge Class in Open Badges 3.0)
- Credential: Issued badge/certificate (Badge Assertion in Open Badges 3.0)
- Profile: User profile (issuer or recipient)
- Evidence: Supporting documentation for credentials
- Endorsement: Third-party validation of credentials
- Revocation List: List of revoked credentials
For complete API documentation, access the Strapi admin panel at http://localhost:1337/admin after setup.
Testing
Frontend Tests
Unit Tests (Vitest):
cd src/frontend npm run test:unit # Run once npm run test:unit:watch # Run in watch mode
End-to-End Tests (Playwright):
cd src/frontend
npm run test:e2eE2E tests cover:
- User registration and login flows
- Badge issuance workflow
- Credential verification
- Dashboard functionality
- Navigation and routing
Backend Tests
The backend uses Strapi's testing framework. Tests can be run from the backend directory:
Deployment
Docker Deployment
The easiest way to deploy Certo is using Docker Compose:
This will start all required services (backend, frontend, and database) in production mode.
Manual Deployment
Backend
cd src/backend
npm install
npm run build
npm startFrontend
cd src/frontend
npm install
npm run build
npm startEnvironment Variables for Production
Make sure to set secure values for:
ADMIN_JWT_SECRET- Strong random string for admin authenticationJWT_SECRET- Strong random string for user authenticationAPP_KEYS- Comma-separated list of random stringsDATABASE_PASSWORD- Secure database password- Update
FRONTEND_URLandNUXT_PUBLIC_API_URLwith your production URLs
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add some amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
License
This project is licensed under the GNU Affero General Public License v3.0 - see the LICENSE file for details.
Acknowledgments
- Open Badges 3.0 Specification
- Verifiable Credentials Data Model
- Strapi
- Nuxt 3
- Una UI
- SchrΓΆdinger Hat
