🏰 Castle of Keys: API-First Access Control in a Physical-Digital Game
James Moro

James Moro @jamesrmoro

About: 🎓 Computer Engineer | 📢 Advertising Specialist | 💻 Front-End Developer I combine creative storytelling with modern front-end technologies. #PWA #TWA #JavaScript #HTML5 #CSS3 #FrontEnd #GameDev

Location:
Brazil
Joined:
Nov 29, 2019

🏰 Castle of Keys: API-First Access Control in a Physical-Digital Game

Publish Date: May 3
58 22

This is a submission for the Permit.io Authorization Challenge: API-First Authorization Reimagined

Table of Contents

What I Built

Castle of Keys is an interactive, real-world access control game inspired by medieval castles and powered by externalized authorization using Permit.io.

Players assume roles like King, Cook, or Servant and attempt to access different levels of a castle. Access is controlled by external policies — not hardcoded logic.


🔄 How It Works (Step-by-Step Flow)

  1. The player presents an RFID card to the reader connected to the ESP32.
  2. The ESP32 reads the UID and sends a request to proxy.php, including the UID and desired action (e.g., access_floor_2).
  3. The proxy.php script securely forwards the request to the Permit.io API using a private token.
  4. Permit.io returns whether the access is allowed ("allow": true) or not.
  5. The ESP32 interprets the response and activates the corresponding LED:
    • ✅ Green = Access Granted
    • ❌ Red = Access Denied
  6. In parallel, the ESP32 sends the log to log.php — used for visual display or debugging in the web interface.

⚠️ Note: log.php is not required for Permit.io to function. It’s used to display access attempts inside the game UI.


🎮 Demo

👉 Watch the full walkthrough demo (Web + Hardware):

🎮 Or test the web version (no hardware required): Try the Castle of Keys (Web Demo)


💡 My Journey

This project started as an idea to bring access control to life through gamification. I wanted to create something more than just a UI button or a permission table — something tangible, physical, and interactive. That’s why I decided to integrate real hardware like RFID readers and, soon, biometric sensors, to make the experience both fun and immersive.


🔐 API-First Authorization

Below is the actual .ino code running on my ESP32. It reads an RFID card using the RC522 module, sends the UID to a secure PHP proxy, and receives a real-time authorization decision from Permit.io.

🔌 ESP32 Code (Arduino)

#include <WiFi.h>
#include <HTTPClient.h>
#include <SPI.h>
#include <MFRC522.h>

const char* ssid = "YOUR_WIFI_NAME";
const char* password = "YOUR_WIFI_PASSWORD";


const char* permitUrl = "https://example.com/api/proxy.php"; // your private endpoint
const char* logUrl = "https://example.com/app/log.php";

#define RST_PIN 22
#define SS_PIN  21

MFRC522 rfid(SS_PIN, RST_PIN);

void setup() {
  Serial.begin(115200);
  SPI.begin();
  rfid.PCD_Init();

  WiFi.begin(ssid, password);
  Serial.print("Connecting to WiFi");
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("\nWiFi connected!");
}

void loop() {
  if (!rfid.PICC_IsNewCardPresent() || !rfid.PICC_ReadCardSerial()) {
    return;
  }

  String uid = "";
  for (byte i = 0; i < rfid.uid.size; i++) {
    uid += String(rfid.uid.uidByte[i], HEX);
  }
  uid.toUpperCase();

  Serial.print("Card detected: ");
  Serial.println(uid);

  // Make Permit.io authorization request
  if (WiFi.status() == WL_CONNECTED) {
    HTTPClient http;
    http.begin(permitUrl);
    http.addHeader("Content-Type", "application/json");

    String payload = "{\"user\":{\"key\":\"" + uid + "\"},\"action\":\"" + action + "\",\"resource\":{\"type\":\"document\",\"tenant\":\"devs\"},\"context\":{}}";

    int httpResponseCode = http.POST(payload);

    if (httpResponseCode > 0) {
      String response = http.getString();
      Serial.println("Permit.io response: " + response);

      if (response.indexOf("\"allow\":true") > 0) {
        Serial.println("✅ Access granted");
        accessGranted = true;
        // digitalWrite(GREEN_LED, HIGH);
      } else {
        Serial.println("❌ Access denied");
        // digitalWrite(RED_LED, HIGH);
      }

    } else {
      Serial.print("Error on sending request: ");
      Serial.println(httpResponseCode);
    }

    http.end();

    // Send access log
    HTTPClient logHttp;
    logHttp.begin(logUrl);
    logHttp.addHeader("Content-Type", "application/json");

    String logPayload = "{\"uid\":\"" + uid + "\",\"action\":\"" + action + "\",\"status\":\"" + (accessGranted ? "granted" : "denied") + "\"}";
    logHttp.POST(logPayload);
    logHttp.end();
  }

  delay(3000); // Prevent repeated scans
}
Enter fullscreen mode Exit fullscreen mode

PHP Proxy for Permit.io (ESP32 Integration)

To keep your Permit.io API key safe, I created a simple proxy.php file. The ESP32 sends a request to this PHP script instead of calling Permit.io directly.

Here’s the full code:

<?php
// proxy.php - Receives data from ESP32 and checks permission via Permit.io

// Read the incoming JSON from ESP32
$body = file_get_contents('php://input');
$data = json_decode($body, true);

// Prepare the payload for Permit.io
$payload = json_encode([
  "user" => [
    "key" => $data['user']  // UID from RFID card
  ],
  "action" => $data['action'], // Example: "access_floor_1"
  "resource" => [
    "type" => "document",   // Replace with your configured resource type
    "tenant" => "devs"      // Tenant ID (if applicable)
  ],
  "context" => new stdClass() // Additional context (empty for now)
]);

// Send the request to Permit.io
$ch = curl_init();

curl_setopt($ch, CURLOPT_URL, "https://api.permit.io/v2/allowed");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $payload);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
  "Authorization: Bearer YOUR_PERMIT_API_KEY", // Replace with your Permit.io API key
  "Content-Type: application/json"
]);

$response = curl_exec($ch);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

// Return the result back to the ESP32
http_response_code($http_code);
echo $response;
Enter fullscreen mode Exit fullscreen mode

✅ Conclusion

This project shows how easy it is to integrate real-world hardware with Permit.io. With just a few lines of code and external policies, you can control access securely — without hardcoding anything.

Comments 22 total

  • Aidityas Adhakim
    Aidityas AdhakimMay 4, 2025

    Very neat!

  • Bridget Amana
    Bridget AmanaMay 4, 2025

    This is so cool

  • Frederick Pellerin
    Frederick PellerinMay 4, 2025

    That's the most nerdy project I've seen. Wow... Loving it!

    • James Moro
      James MoroMay 4, 2025

      Thanks ;) It was a fun project to build and learn from — totally worth the time!

  • Nevo David
    Nevo DavidMay 4, 2025

    This is actually cool, I like seeing hardware hooked up to APIs like that - makes me wanna mess around with RFID and build something myself. You think people will ever trust this kind of access control as much as the old-school key and lock?

    • James Moro
      James MoroMay 4, 2025

      Thanks ;)

      Basic RFID can be cloned, sure — but with encryption, biometrics, and cloud validation, it gets a lot more secure. Many modern locks use RFID nowadays, and while safer setups tend to cost more, they can offer a good level of trust, depending on how it’s done.

  • davinceleecode
    davinceleecodeMay 5, 2025

    This project is impressive and truly one of a kind. It's clear you put a lot of effort into it—amazing work!

    • James Moro
      James MoroMay 8, 2025

      Thanks ;) I had a blast building it—happy you liked it!

  • Kiran Naragund
    Kiran NaragundMay 5, 2025

    Awesome ⚡

  • Aleksandr Heinlaid
    Aleksandr HeinlaidMay 5, 2025

    Nice project! really like the mix of physical access with API-based permissions - feels like a solid base for real-world use. The castle theme makes it more fun and relatable too ;)

    • James Moro
      James MoroMay 8, 2025

      Thanks ;) The idea was to mix reality with a fun twist — I'm glad you liked the castle theme!

  • nadeem zia
    nadeem ziaMay 5, 2025

    Amazing work

  • Professor   Reza   Sanaye
    Professor Reza SanayeMay 5, 2025

    There’s a way to cloud this whole project free by means of natural nerve-learning cloning . This kind of access encrypts even the clone validation itself . The resultant contents are typically saved as disk image semi-coded files . Cryptanalysis cannot “bypass” nonlinear aspects of your code(s) . They say AES’s developers actually managed to offer the design of the round transformation amenable to clear-clone analysis.The aim of this latter algorithmization is a process of the wide trail strategy implementation in a round Complex Function without its separation into linear and nonlinear parts.

  • Zeal AI
    Zeal AI May 8, 2025

    Amazing product!!!

  • Adamson Keyy
    Adamson KeyyMay 8, 2025

    Cool

  • Grace Landon
    Grace LandonMay 8, 2025

    I was so lucky to win the $1 million prize in the lottery. I have been playing the powerball lottery for about 20 years, and i didn't win any big amount until Dr. Lucas helped me with his spiritual winning numbers, I thought it was all fake until he gave me the numbers and directed me on how to play. He gave me assurance that I was going to win and asked me to give him 48 hours to finish his work, which I did. The third day, he gave me the numbers and gave me instructions on how to play, and luckily, I won. I want to let everyone who is reading this to know that this spell really works and you can also be a winner if you give it a try to see for yourself. The moment you contact Dr Lucas for help is the end of suffering in your life, he has been helping people around the world and I'm happy that I'm among those who has benefited from his great work he's doing, you can reach him if you really want to win the lottery Email: Drlucasspelltemple@gmail.com Or WhatsApp +234 904 794 3567 Thank You 

Add comment