Skip to content

baseid-siop

Implements SIOPv2 (Self-Issued OpenID Provider v2) for DID-based authentication. Provides both the wallet-side provider (SelfIssuedProvider) and the verifier-side relying party (RelyingParty), supporting same-device and cross-device flows, DID and JWK Thumbprint subject syntax, and combined SIOPv2+OID4VP requests.

  • DID-Based Authentication — Self-issued ID tokens where iss == sub == DID (no centralized identity provider)
  • SelfIssuedProvider — Wallet-side: parse requests, validate scopes/nonces, create signed ID token JWTs
  • RelyingParty — Verifier-side: build authentication requests, verify ID tokens with 7 spec-mandated validation steps
  • Combined SIOPv2+OID4VP — Single request for both authentication and credential presentation
  • Cross-Device Flowdirect_post response mode with response_uri for QR-code-based authentication
  • Subject Syntax Types — DID methods (did:key, did:web, etc.) and JWK Thumbprint URIs (RFC 9278)
use baseid_siop::provider::SelfIssuedProvider;
use baseid_siop::relying_party::RelyingParty;
use baseid_crypto::KeyPair;
use baseid_core::types::KeyType;
use baseid_did::DidKeyResolver;
// --- Relying Party creates an authentication request ---
let rp = RelyingParty {
client_id: "https://rp.example.com".to_string(),
redirect_uri: "https://rp.example.com/cb".to_string(),
};
let request = rp.create_authentication_request("unique-nonce-123");
// --- Wallet (Self-Issued Provider) responds ---
let kp = KeyPair::generate(KeyType::Ed25519)?;
let holder_did = "did:key:z6Mk...".to_string();
let provider = SelfIssuedProvider::new(&kp, holder_did);
let parsed = provider.parse_request(&serde_json::to_string(&request)?)?;
let id_token_jwt = provider.create_id_token(&parsed)?;
// --- Relying Party verifies the ID token ---
let resolver = DidKeyResolver;
let verified = rp.verify_id_token(&id_token_jwt, "unique-nonce-123", &resolver).await?;
assert_eq!(verified.nonce, "unique-nonce-123");
FieldDescription
response_type"id_token" for SIOPv2, "id_token vp_token" for combined
client_idRP identifier (URL or DID)
scopeMust include "openid"
nonceReplay protection (required, non-empty)
response_mode"fragment" (default), "direct_post", "form_post"
redirect_uriSame-device callback
response_uriCross-device direct_post endpoint
presentation_definitionOID4VP presentation definition (combined flow)

The RelyingParty::verify_id_token() method implements all mandatory validation steps from SIOPv2 spec Section 11.1:

  1. Self-issued checkiss must equal sub
  2. Audience matchaud must equal RP’s client_id
  3. Subject syntax — Identify DID or JWK Thumbprint URI
  4. Signature verification — Resolve DID document, extract key, verify JWT
  5. Subject claim — Validate the subject identifier
  6. Expiration check — Token must not be expired
  7. Nonce validation — Nonce must match the authentication request
TypeDescription
SelfIssuedProviderWallet-side: parses requests and creates signed ID tokens
RelyingPartyVerifier-side: builds requests and verifies ID tokens
AuthenticationRequestSIOPv2 request with scope, nonce, response mode
SelfIssuedIdTokenID token claims: iss, sub, aud, exp, iat, nonce, sub_jwk
VerifiedIdTokenResult of successful verification: sub, iss, nonce, claims
SubjectSyntaxTypeJwkThumbprint or Did(method)
use baseid_siop::SubjectSyntaxType;
let did = SubjectSyntaxType::Did("key".to_string());
assert_eq!(did.to_metadata_value(), "did:key");
let jwk = SubjectSyntaxType::JwkThumbprint;
assert_eq!(jwk.to_metadata_value(), "urn:ietf:params:oauth:jwk-thumbprint");
  • baseid-did — DID resolution for key discovery during verification
  • baseid-crypto — JWT signing and key pair generation
  • baseid-oid4vci — OID4VCI credential issuance (often paired with SIOPv2)
  • baseid-wallet-core — Wallet orchestrator composing SIOPv2 with credential flows