← Back to Projects

Extending Pika: Multi-Tenant Proxy Access Control

Modifying Pika (open source ngrok alternative) to support organization-based session management with minimal token overhead.

The Challenge

At Olostep, we needed a reverse proxy solution that could allow organization admins to access multiple user sessions while keeping authentication tokens small for URL sharing. Pika, an open source ngrok alternative written in Go, was almost perfect but lacked multi-tenant session management.

What is Pika?

Pika is a self-hosted reverse proxy that creates secure tunnels from public URLs to local services - essentially an open source alternative to ngrok. It handles TLS termination, connection multiplexing, and basic authentication, but its session model was one user to one session.

The Requirement

We needed organization-level access control where an admin could access sessions belonging to users in their organization without requiring multiple separate authentications.

Access Pattern:

Organization Admin (Alice)
  ├─ Can access own sessions
  └─ Can access sessions of users in her org:
      ├─ Bob's sessions
      ├─ Carol's sessions
      └─ Dave's sessions

Constraints:

Solution Approach

Token Design

Instead of Pika's default user-only token, we implemented JWT tokens that encode user ID, organization ID, and role. To keep tokens short, we used compact field names and base64url encoding.

Session Resolution

Modified Pika's session lookup to check not just if the user owns the session, but if they have organization-level access. This required changes to how sessions are stored and retrieved.

Organization Registry

Enhanced the session storage to track which organization each session belongs to, allowing efficient lookups when an admin requests access to sessions within their org.

Implementation

The modifications focused on three areas:

  1. Token validation - Parse and validate JWT tokens with organization claims
  2. Session resolution - Check organization relationships before granting access
  3. Session storage - Track organization membership for each session

We kept the changes minimal and well-abstracted so they could potentially be contributed back to Pika's mainline (though they ended up being too specific for general use).

Challenges

Token Size: JWT tokens can get large. We solved this with short field names, omitting empty fields, and careful encoding choices. Tokens stayed under 200 characters.

Performance: JWT validation on every request adds latency. We implemented in-memory token caching with TTL, achieving 95%+ cache hit rates.

Testing: Multi-tenant permission logic is complex and error-prone. We built comprehensive test coverage for all access patterns.

Results

Performance: Token validation under 1ms with caching, no measurable overhead on connection routing

Scale: Successfully handles 10,000+ concurrent sessions

Security: Organization isolation maintained, no privilege escalation issues

Maintainability: Clean abstraction made it easy to maintain separate from core Pika code

Lessons Learned

Open Source Modification vs Building From Scratch: Pika gave us 80% of what we needed. Building a reverse proxy from scratch would have taken months. Modifying Pika took 2 weeks.

Token Design Is Critical: First iteration had tokens over 400 characters (too long for URLs). Took several iterations to get down to under 200 characters with compact field names and encoding.

JWT Performance Without Caching Is Terrible: Initial implementation validated JWT on every request. 50ms+ overhead. Added in-memory cache with TTL, got to under 1ms. Cache hit rate: 95%+.

Test Multi-Tenant Permissions Thoroughly: This is where bugs hide. Built comprehensive test matrix of all access patterns (own session, org member, different org, admin vs user). Found 3 authorization bypass bugs during testing.

Keep Modifications Minimal: Resisted temptation to refactor Pika's codebase. Made targeted changes, kept abstractions clean. This made it possible to merge upstream updates without conflicts.

Document Decisions: Wrote detailed comments explaining WHY we made each architectural choice. Six months later when revisiting, this context was invaluable.

Upstream Contribution Attempt Was Valuable Even Though Rejected: Pika maintainers said feature was too specific. But the dialog helped us understand their codebase better and validated our approach.

Open Source Contribution

We attempted to contribute this back to Pika but it was too specific for their use case. However, we documented our approach in a GitHub discussion and helped other teams implement similar features.

Technologies

This project showed that understanding a codebase deeply and making targeted modifications can solve problems without reinventing the wheel.