Skip to main content

Identity and Sessions coverage

Personal-agent and user identity, Sessions, and proof of possession (§4.1 to §4.3). Upstream: personalagentprotocol.org/docs/spec.

27 entries: 26 implemented, 1 not-applicable. Each row is one atomic statement of the upstream text, with the SDK symbols that implement it (Python; TypeScript mirrors them), the tests and shared conformance cases that show it, and its status.

IDSectionLevelRoleRequirementSDK symbolTestsStatus
PAP-4.1-01§4.1MUSTpersonal-agentA Personal Agent's client_id MUST be an HTTPS URL that returns its metadata document.ClientMetadata.validate_urls
AgentIdentity.website
test_identity.py::test_fetches_metadata_and_public_jwksimplemented
PAP-4.1-02§4.1MUSTbothclient_id MUST equal the URL the document was fetched from.AgentIdentityClient.fetch_metadatatest_identity.py::test_rejects_substituted_client_id
test_identity.py::test_client_metadata_does_not_follow_redirects
security.client-assertion-alg-none
implemented
PAP-4.1-03§4.1MUSTbothjwks_uri and every entry in redirect_uris MUST be HTTPS URLs on the same domain as client_id.ClientMetadata.validate_same_domain_urlstest_models.py::test_client_metadata_requires_same_domain_for_security_urls
test_identity.py::test_rejects_cross_domain_jwks_redirect
implemented
PAP-4.2-01§4.2MUSTpersonal-agentThe Personal Agent MUST give each of its Users a User ID for each Company, where a Company is identified by its auth.issuer (3.2).SqlitePairwiseUserIdStore
PAIRWISE_USER_ID_STORES
test_pairwise.py::test_persists_stable_pairwise_ids_by_exact_tenant_user_and_issuer
test_conformance.py::test_python_agent_python_company_over_tls
lifecycle.parallel-sessions
implemented
PAP-4.2-02§4.2MUST NOTpersonal-agentIt MUST NOT contain or be derived from personal information, such as an email address, phone number, or name, even with a keyed hash.generate_pairwise_user_idtest_sessions.py::test_generates_random_pairwise_identifier_without_personal_dataimplemented
PAP-4.2-03§4.2MUSTcompanyThe Company chooses the value, and it MUST be greater than 0.CompanyService._issue
SessionToken
test_conformance.py::test_python_agent_python_company_over_tls
lifecycle.signed-out-session
implemented
PAP-4.2-04§4.2SHOULDcompanySession Tokens SHOULD last hours, not days.CompanyConfig.session_lifetimetest_conformance.py::test_python_agent_python_company_over_tls
lifecycle.signed-out-session
implemented
PAP-4.2-05§4.2MUST NOTpersonal-agentPersonal Agents MUST NOT depend on their contents; everything they need is in the response.SessionTokentest_sessions.py::test_parses_session_token_as_opaque_secret
test_conformance.py::test_python_agent_python_company_over_tls
lifecycle.signed-out-session
implemented
PAP-4.2-06§4.2MUSTcompanyA Company MAY include its own Session credentials in a token so its existing systems can read them. If it does, it MUST encrypt the token.CompanyService._issue—not-applicable: The reference company issues random opaque tokens (sat_…) that carry nothing; the Session is looked up by the token's digest.
PAP-4.3-01§4.3MUSTpersonal-agentAPI calls and conversations MUST carry the Session Token in the Authorization header with the DPoP scheme, together with a DPoP Proof (RFC 9449).DpopHttpClient.requesttest_transport.py::test_nonce_retry_and_redirect_each_use_fresh_bound_proof
test_conformance.py::test_python_agent_python_company_over_tls
conversations.start-and-reply
security.dpop-missing
implemented
PAP-4.3-02§4.3MUSTcompanyOn every request, it MUST check that: The proof's signature verifies with the key in its header.verify_dpop_proof
CompanyService._dpop
CompanyService._caller
test_crypto.py::test_creates_and_verifies_bound_dpop_proof_once
test_crypto.py::test_rejects_dpop_request_or_token_mismatch
test_conformance.py::test_python_agent_python_company_over_tls
security.dpop-alg-none
security.dpop-wrong-signature
implemented
PAP-4.3-03§4.3MUSTcompanyOn every request, it MUST check that: That key is the one the Session Token is bound to.verify_dpop_proof
CompanyService._dpop
CompanyService._caller
test_crypto.py::test_creates_and_verifies_bound_dpop_proof_once
test_crypto.py::test_rejects_dpop_request_or_token_mismatch
test_conformance.py::test_python_agent_python_company_over_tls
security.dpop-other-key
implemented
PAP-4.3-04§4.3MUSTcompanyOn every request, it MUST check that: htm and htu match the request.verify_dpop_proof
CompanyService._dpop
CompanyService._caller
test_crypto.py::test_creates_and_verifies_bound_dpop_proof_once
test_crypto.py::test_rejects_dpop_request_or_token_mismatch
test_conformance.py::test_python_agent_python_company_over_tls
security.dpop-method-mismatch
security.dpop-url-mismatch
implemented
PAP-4.3-05§4.3MUSTcompanyOn every request, it MUST check that: iat is within the Company's acceptance window, such as one minute.verify_dpop_proof
CompanyService._dpop
CompanyService._caller
test_crypto.py::test_creates_and_verifies_bound_dpop_proof_once
test_crypto.py::test_rejects_dpop_request_or_token_mismatch
test_conformance.py::test_python_agent_python_company_over_tls
security.dpop-stale
implemented
PAP-4.3-06§4.3MUSTcompanyOn every request, it MUST check that: It hasn't accepted the same jti within that window.verify_dpop_proof
CompanyService._dpop
CompanyService._caller
test_crypto.py::test_creates_and_verifies_bound_dpop_proof_once
test_crypto.py::test_rejects_dpop_request_or_token_mismatch
test_conformance.py::test_python_agent_python_company_over_tls
security.dpop-replay
implemented
PAP-4.3-07§4.3MUSTcompanyOn every request, it MUST check that: ath matches the Session Token.verify_dpop_proof
CompanyService._dpop
CompanyService._caller
test_crypto.py::test_creates_and_verifies_bound_dpop_proof_once
test_crypto.py::test_rejects_dpop_request_or_token_mismatch
test_conformance.py::test_python_agent_python_company_over_tls
security.token-dpop-with-ath
security.dpop-token-hash-mismatch
implemented
PAP-4.3-08§4.3MUSTpersonal-agentPersonal Agents MUST support nonces.DpopHttpClient.request
SessionClient._request
AccountTokenClient._post_with_nonce
test_sessions.py::test_retries_once_with_a_fresh_dpop_nonce_and_assertions
test_transport.py::test_nonce_retry_and_redirect_each_use_fresh_bound_proof
test_accounts.py::test_one_dpop_nonce_retry_with_a_fresh_proof
implemented
PAP-4.3-09§4.3MUSTpersonal-agentTo get one for an existing Session, the Personal Agent sends the request that renews the Session's token (4.2, or 4.8 for a signed-in Session) without the DPoP header, and MUST include resource set to the MCP server's url from poppy.json, as MCP authorization requires.SessionClient.bearer_for_mcp
AccountTokenClient.bearer_for_mcp
test_mcp_and_web.py::test_a_bearer_is_issued_only_for_the_mcp_url_and_an_existing_session
test_mcp_and_web.py::test_a_signed_in_bearer_reads_and_proposes_through_mcp_the_same_operation
test_conformance.py::test_python_agent_python_company_over_tls
lifecycle.mcp-bearer-for-its-url
implemented
PAP-4.3-10§4.3MUSTcompanyCompanies MUST accept Bearer Session Tokens only on their MCP APIs (section 6), and MUST require DPoP everywhere else.CompanyService._caller
CompanyService._bearer_caller
CompanyService._token
McpBearerAuth
test_mcp_and_web.py::test_a_bearer_token_is_refused_everywhere_but_its_mcp_server
test_conformance.py::test_python_agent_python_company_over_tls
lifecycle.mcp-bearer-only-at-mcp
security.dpop-token-as-bearer
implemented
PAP-4.3-11§4.3MUSTcompanyCompanies MUST accept Bearer Session Tokens only on their MCP APIs (section 6), and MUST require DPoP everywhere else.CompanyService._caller
CompanyService._token
test_conformance.py::test_python_agent_python_company_over_tls
security.token-request-without-dpop
security.dpop-missing
security.dpop-token-as-bearer
implemented
PAP-4.3-12§4.3MUSTcompanyCompanies MUST accept the token in the Authorization header without requiring cookies.CompanyService._callertest_conformance.py::test_python_agent_python_company_over_tls
security.authorization-header-without-cookies
implemented
PAP-4.3-13§4.3MUSTpersonal-agentPersonal Agents MUST send a Session Token on every API and conversation request, and MUST NOT leave it out to appear to the Company as a person on their own.DpopHttpClient.request
ConversationClient
ApiClient.call
test_conversations.py::test_start_and_continue_preserve_message_ids_and_parse_waited_eventsimplemented
PAP-4.3-14§4.3MUST NOTpersonal-agentPersonal Agents MUST send a Session Token on every API and conversation request, and MUST NOT leave it out to appear to the Company as a person on their own.DpopHttpClient.requesttest_conversations.py::test_start_and_continue_preserve_message_ids_and_parse_waited_eventsimplemented
PAP-4.3-15§4.3MUSTpersonal-agentWhenever the Personal Agent gets a new Session Token for a Session, it MUST use the new token from then on.SessionClient.renew
AccountTokenClient.refresh
test_conformance.py::test_python_agent_python_company_over_tls
lifecycle.renew-signed-out
implemented
PAP-4.3-16§4.3MUST NOTpersonal-agentPersonal Agents MUST NOT send tokens in a URL, and Companies MUST NOT accept them from one.DpopHttpClient.request
ConversationClient._query
test_transport.py::test_nonce_retry_and_redirect_each_use_fresh_bound_proof
test_conformance.py::test_python_agent_python_company_over_tls
security.token-in-url-refused
implemented
PAP-4.3-17§4.3MUST NOTcompanyPersonal Agents MUST NOT send tokens in a URL, and Companies MUST NOT accept them from one.CompanyService._callertest_conformance.py::test_python_agent_python_company_over_tls
security.token-in-url-refused
implemented
PAP-4.3-18§4.3MUSTpersonal-agentA Company that limits how often a Personal Agent can make requests returns HTTP 429 with a Retry-After header when a request goes over the limit, on any of its endpoints, APIs, conversations, or website. The Personal Agent MUST wait at least that long before sending the request again.ApiClient.call
ConversationClient._rejected
SessionClient._request
test_mediated.py::test_rate_limited_is_reported_with_retry_after_and_no_credential
test_fixtures.py::test_local_fixture_case
lifecycle.rate-limit-retry-after
implemented

Conformance case IDs name protocol/fixtures/conformance cases; see the conformance report for their outcome in every language pairing.