DEV Community

Cover image for ๐Ÿฐ Castle of Keys: API-First Access Control in a Physical-Digital Game
James Moro
James Moro Subscriber

Posted on

30 7 6 7 6

๐Ÿฐ Castle of Keys: API-First Access Control in a Physical-Digital Game

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.

ACI image

ACI.dev: The Only MCP Server Your AI Agents Need

ACI.devโ€™s open-source tool-use platform and Unified MCP Server turns 600+ functions into two simple MCP tools on one serverโ€”search and execute. Comes with multi-tenant auth and natural-language permission scopes. 100% open-source under Apache 2.0.

Star our GitHub!

Top comments (21)

Collapse
 
nevodavid profile image
Nevo David โ€ข

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?

Collapse
 
jamesrmoro profile image
James Moro โ€ข

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.

Collapse
 
dev_kiran profile image
Kiran Naragund โ€ข

Awesome โšก

Collapse
 
jamesrmoro profile image
James Moro โ€ข

Thanks ;)

Collapse
 
aidityasadhakim profile image
Aidityas Adhakim โ€ข

Very neat!

Collapse
 
jamesrmoro profile image
James Moro โ€ข

Thanks ;)

Collapse
 
davinceleecode profile image
davinceleecode โ€ข

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

Collapse
 
jamesrmoro profile image
James Moro โ€ข

Thanks ;) I had a blast building itโ€”happy you liked it!

Collapse
 
nadeem_zia_257af7e986ffc6 profile image
nadeem zia โ€ข

Amazing work

Collapse
 
jamesrmoro profile image
James Moro โ€ข

Thanks ;)

Collapse
 
therealfredp3d profile image
Frederick Pellerin โ€ข

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

Collapse
 
jamesrmoro profile image
James Moro โ€ข

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

Collapse
 
bridget_amana profile image
Bridget Amana โ€ข

This is so cool

Collapse
 
jamesrmoro profile image
James Moro โ€ข

Thanks ;)

Collapse
 
zealai profile image
Zeal AI โ€ข

Amazing product!!!

Collapse
 
jamesrmoro profile image
James Moro โ€ข

Thanks ;)

Collapse
 
adamson_keyy_3b37b1080c66 profile image
Adamson Keyy โ€ข

Cool

Collapse
 
jamesrmoro profile image
James Moro โ€ข

Thanks ;)

Collapse
 
cyrus_zargaani_6a19e0c497 profile image
Professor Reza Sanaye โ€ข

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.

Some comments may only be visible to logged-in visitors. Sign in to view all comments.

Image of Quadratic

Free AI chart generator

Upload data, describe your vision, and get Python-powered, AI-generated charts instantly.

Try Quadratic free

๐Ÿ‘‹ Kindness is contagious

Engage with a wealth of insights in this thoughtful article, valued within the supportive DEV Community. Coders of every background are welcome to join in and add to our collective wisdom.

A sincere "thank you" often brightens someoneโ€™s day. Share your gratitude in the comments below!

On DEV, the act of sharing knowledge eases our journey and fortifies our community ties. Found value in this? A quick thank you to the author can make a significant impact.

Okay