---
title: "Security Baked Into the JVM: two Subjects, one call"
url: https://daily.dev/posts/security-baked-into-the-jvm-two-subjects-one-call-fifkkyz8a
source_url: https://blog.frankel.ch/security-baked-into-jvm/3
type: article
source: "A Java geek"
published: 2026-08-09T16:41:41.254Z
updated: 2026-08-09T16:42:17.426Z
tags: ["java", "authentication"]
reading_time: 6
upvotes: 2
comments: 2
language: en
---

> ## Documentation Index
> Fetch the complete documentation index at: https://daily.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Security Baked Into the JVM: two Subjects, one call

**[A Java geek](https://daily.dev/sources/frankel)** · 6 min read · 2 upvotes · 2 comments

## Summary

DirtyChai, a JVM security framework built on JGDMS, introduces a sealed Subject hierarchy with two distinct identity types: WorkerSubject (process-level, SPIFFE-backed) and UserSubject (per-request, JWT/OIDC). WorkerSubject is baked into every ProtectionDomain at class load time and is ambient across all permission checks, while UserSubject travels via ScopedValue and is bound per request using Subject.callAs(). SPIFFE workload identity replaces traditional keystores — short-lived X.509 SVIDs are managed by a SPIRE agent, rotated automatically without JVM restarts. During a dispatched RPC, up to three identity layers coexist: the local process worker, the remote client's process context (verified via SHA-256 digest), and the per-request user identity. A single call can carry up to 16 user Subjects. The design deliberately separates identity from privilege, retiring doAs/doAsPrivileged in favor of callAs plus explicit doPrivileged boundaries.

## Full article

daily.dev links to this article rather than hosting it. Read it at the original source: <https://blog.frankel.ch/security-baked-into-jvm/3>

## Questions this post answers

### What is the difference between Subject.callAs() and Subject.doAs() in Java JAAS and why is doAs being deprecated?

callAs() binds identity on a ScopedValue and that identity survives doPrivileged boundaries, keeping who-you-are and what-privileges-code-runs-with orthogonal. doAs() couples them: used merely to run privileged, it also drops the user by rebinding the subject and suppressing the enclosing one. Dropping the user becomes an unintended side effect of a code boundary rather than a deliberate choice. doAs and doAsPrivileged are retained only for legacy JAAS and Kerberos GSS interop.

_Java teams migrating JAAS-based auth track these API shifts on daily.dev before they hit production._

### How does SPIFFE workload identity work without keystores in a Java JVM service?

A SpiffeCredentialManager opens the SPIRE Workload API socket on startup and populates an in-memory Subject with the current X.509 certificate and private key — no filesystem keystore or PKCS#12 files. The default SVID lifetime is about one hour. Credentials rotate automatically when the SVID nears expiry, triggering a policy refresh, all without JVM restarts or manual certificate renewal.

_Engineers replacing keystore-based mTLS with SPIFFE find the tradeoffs covered on daily.dev._

### How does DirtyChai handle unverifiable ProtectionDomains received over the JERI wire in version 23?

Version 23 of AccessControlContextSerializer stopped stripping unverifiable domains before transport. Instead, unverifiable domains are counted as anonCount and reconstructed as anonymous placeholder ProtectionDomains on the receiving JVM — their permission ceilings are preserved without asserting a specific identity. Earlier versions stripped them, which was recognized as an implicit privilege escalation.

_Developers working with JGDMS serialization changes watch for breaking shifts like this on daily.dev._

## Community discussion

Top comments from developers on daily.dev.

**@agustinbarrientos** · 0 upvotes

> Can application code detect the 16-subject ceiling before dispatch rejects the call?

**@trevorsuna** · 0 upvotes

> Separating workload identity from per-request user identity makes the trust boundaries much clearer, especially with short-lived SPIFFE credentials. The next practical piece is observability: logs and traces should show which identity layer caused a permission decision without leaking token details.

## Similar posts on daily.dev

- [SPIFFE vs. OAuth: Access Control for Nonhuman Identities](https://daily.dev/posts/spiffe-vs-oauth-access-control-for-nonhuman-identities-d6bssojfw) · Security Boulevard · 1 upvotes · 0 comments
- [What Is SPIFFE and How Does It Work?](https://daily.dev/posts/what-is-spiffe-and-how-does-it-work--cfg6ilipr) · Descope · 0 upvotes · 0 comments
- [Identity is the Battleground](https://daily.dev/posts/identity-is-the-battleground-vbiaqrif0) · Cisco · 1 upvotes · 0 comments

---

Tags: [#java](https://daily.dev/tags/java), [#authentication](https://daily.dev/tags/authentication)

[View this post on daily.dev](https://daily.dev/posts/security-baked-into-the-jvm-two-subjects-one-call-fifkkyz8a)
