{"openapi":"3.1.0","info":{"title":"JWTShield","version":"0.0.1"},"paths":{"/v1/health":{"get":{"tags":["health"],"summary":"System health snapshot","operationId":"get_health_v1_health_get","responses":{"200":{"description":"Health snapshot. Always returns 200; read 'status'.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HealthResponse"},"example":{"status":"ok","version":"0.0.1","uptime_seconds":1234.5,"checked_at":1761412800.0,"components":{"api":{"status":"ok"},"profile_registry":{"status":"ok","detail":"1 profile registered"},"jwks_cache":{"status":"ok","detail":"0 cached entries"},"http_client":{"status":"ok"}}}}}}}}},"/v1/inspect/token":{"post":{"tags":["inspect"],"summary":"Inspect Token","operationId":"inspect_token_v1_inspect_token_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InspectRequest"}}},"required":true},"responses":{"200":{"description":"Token decoded successfully (NOT validated).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InspectResponse"},"example":{"decoded":{"header":{"alg":"HS256","typ":"JWT"},"payload":{"iss":"https://issuer.example.com","aud":["api://backend"],"sub":"user-42","exp":9999999999},"signature_segment":"KJ2lp..."},"validated":false,"warning":"Token was decoded only. Decoded does not mean validated: signature, issuer, audience, and claim policy were not checked.","suspicious_warnings":[]}}}},"422":{"description":"Request body failed validation (e.g. missing token).","content":{"application/json":{"example":{"detail":[{"loc":["body","token"],"msg":"Field required","type":"missing"}]}}}}}}},"/v1/validate/jwt":{"post":{"tags":["validate"],"summary":"Validate Jwt","operationId":"validate_jwt_v1_validate_jwt_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidateRequest"}}},"required":true},"responses":{"200":{"description":"JWT validation result. HTTP 200 is returned for both valid and invalid tokens; valid=false cases carry structured findings.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VerifyResult"},"example":{"valid":true,"statuses":{"signature":"pass","issuer":"pass","audience":"pass","algorithm":"pass","time":"pass","required_claims":"pass"},"findings":[],"summary":"Token is valid: signature verified, issuer/audience/time/required-claims all passed."}}}},"422":{"description":"Request body failed validation.","content":{"application/json":{"example":{"detail":[{"loc":["body"],"msg":"Exactly one of 'policy' or 'issuer_profile_id' must be provided.","type":"value_error"}]}}}}}}},"/v1/providers/discover":{"post":{"tags":["discover"],"summary":"Discover","operationId":"discover_v1_providers_discover_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DiscoverRequest"}}},"required":true},"responses":{"200":{"description":"Provider discovery result. HTTP 200 is returned for both successful and failed discovery; failures surface as structured findings with status != 'ok'.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DiscoverResponse"},"example":{"discovery":{"issuer":"https://issuer.example.com","jwks_uri":"https://issuer.example.com/.well-known/jwks.json","authorization_endpoint":"https://issuer.example.com/oauth2/authorize","token_endpoint":"https://issuer.example.com/oauth2/token","supported_algs":["RS256","ES256"]},"jwks_reachability":"reachable","findings":[],"status":"ok"}}}},"422":{"description":"Request body failed validation (e.g. missing issuer).","content":{"application/json":{"example":{"detail":[{"loc":["body","issuer"],"msg":"Field required","type":"missing"}]}}}}}}},"/v1/test/auth-regression":{"post":{"tags":["regression"],"summary":"Auth Regression","operationId":"auth_regression_v1_test_auth_regression_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AuthRegressionRequest"}}},"required":true},"responses":{"200":{"description":"Auth regression suite result. suite_status is 'pass' only when every check in the batch is valid.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AuthRegressionResponse"},"example":{"suite_status":"pass","passed":2,"failed":0,"results":[{"valid":true,"statuses":{"signature":"pass","issuer":"pass","audience":"pass","algorithm":"pass","time":"pass","required_claims":"pass"},"findings":[],"summary":"Token is valid."}],"request_id":"0123456789abcdef0123456789abcdef"}}}},"422":{"description":"Request body failed validation (e.g. empty checks list).","content":{"application/json":{"example":{"detail":[{"loc":["body","checks"],"msg":"List should have at least 1 item after validation, not 0","type":"too_short"}]}}}}}}},"/v1/validate/ci-oidc":{"post":{"tags":["ci-validate"],"summary":"Validate Ci Oidc","operationId":"validate_ci_oidc_v1_validate_ci_oidc_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CiValidateRequest"}}},"required":true},"responses":{"200":{"description":"CI OIDC validation result. Uses the selected provider's preset issuer/audience/claim policies.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VerifyResult"},"example":{"valid":true,"statuses":{"signature":"pass","issuer":"pass","audience":"pass","algorithm":"pass","time":"pass","required_claims":"pass"},"findings":[],"summary":"Token is valid under the github_actions preset."}}}},"422":{"description":"Request body failed validation (unknown provider or missing required field).","content":{"application/json":{"example":{"detail":[{"loc":["body","provider"],"msg":"Input should be 'github_actions' or 'gitlab'","type":"literal_error"}]}}}}}}},"/v1/lint/oidc-config":{"post":{"tags":["lint"],"summary":"Lint Oidc Config Endpoint","operationId":"lint_oidc_config_endpoint_v1_lint_oidc_config_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OidcLintRequest"}}},"required":true},"responses":{"200":{"description":"OIDC configuration lint result with structured findings and remediation guidance. valid=true means no findings were emitted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OidcLintResponse"},"example":{"valid":true,"findings":[],"summary":"OIDC configuration passed all lint checks."}}}},"422":{"description":"Request body failed validation (missing required field).","content":{"application/json":{"example":{"detail":[{"loc":["body","issuer"],"msg":"Field required","type":"missing"}]}}}}}}},"/v1/validate/jwks-rotation":{"post":{"tags":["rotation"],"summary":"Validate Jwks Rotation","operationId":"validate_jwks_rotation_v1_validate_jwks_rotation_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/JwksRotationRequest"}}},"required":true},"responses":{"200":{"description":"JWKS rotation classification result. One of no_change, overlap, or disjoint — with structured findings for operationally notable states.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/JwksRotationResponse"},"example":{"rotation_state":"overlap","findings":[],"summary":"JWKS rotation state: in-progress rotation with key overlap."}}}},"422":{"description":"Request body failed validation (missing previous or current JWKS).","content":{"application/json":{"example":{"detail":[{"loc":["body","previous"],"msg":"Field required","type":"missing"}]}}}}}}},"/v1/presets/{provider}":{"get":{"tags":["presets"],"summary":"Get Provider Preset","operationId":"get_provider_preset_v1_presets__provider__get","parameters":[{"name":"provider","in":"path","required":true,"schema":{"type":"string","title":"Provider"}}],"responses":{"200":{"description":"Prefilled provider preset with issuer and policy template.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProviderPresetTemplate"},"example":{"provider":"github_actions","issuer":"https://token.actions.githubusercontent.com","policy":{"allowed_algs":["RS256"],"audiences":[],"required_claims":["repository","workflow","sub"],"clock_skew_seconds":0},"notes":"Populate audiences with the value your workflow declares via permissions.id-token.audience."}}}},"404":{"description":"Unknown provider preset.","content":{"application/json":{"example":{"detail":"Unknown provider preset: 'bitbucket'. Available: auth0, okta, cognito, github_actions, gitlab."}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}},"components":{"schemas":{"AuthRegressionRequest":{"properties":{"checks":{"items":{"$ref":"#/components/schemas/RegressionCheck"},"type":"array","minItems":1,"title":"Checks"},"fail_on_severity":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Fail On Severity"}},"type":"object","required":["checks"],"title":"AuthRegressionRequest"},"AuthRegressionResponse":{"properties":{"suite_status":{"type":"string","enum":["pass","fail"],"title":"Suite Status"},"passed":{"type":"integer","title":"Passed"},"failed":{"type":"integer","title":"Failed"},"results":{"items":{"$ref":"#/components/schemas/VerifyResult"},"type":"array","title":"Results"},"fail_on_severity":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Fail On Severity"},"request_id":{"type":"string","title":"Request Id"}},"type":"object","required":["suite_status","passed","failed","results","request_id"],"title":"AuthRegressionResponse"},"CiValidateRequest":{"properties":{"token":{"type":"string","minLength":1,"title":"Token"},"provider":{"type":"string","enum":["github_actions","gitlab"],"title":"Provider"},"expected_repository":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Expected Repository"},"expected_ref":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Expected Ref"},"expected_project_path":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Expected Project Path"},"expected_ref_protected":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Expected Ref Protected"}},"type":"object","required":["token","provider"],"title":"CiValidateRequest"},"ComponentHealth":{"properties":{"status":{"type":"string","enum":["ok","degraded","down"],"title":"Status"},"detail":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Detail"}},"type":"object","required":["status"],"title":"ComponentHealth"},"DecodedPayload":{"properties":{"header":{"additionalProperties":true,"type":"object","title":"Header"},"payload":{"additionalProperties":true,"type":"object","title":"Payload"},"signature_segment":{"type":"string","title":"Signature Segment"}},"type":"object","required":["header","payload","signature_segment"],"title":"DecodedPayload"},"DiscoverRequest":{"properties":{"issuer":{"type":"string","minLength":1,"title":"Issuer"}},"type":"object","required":["issuer"],"title":"DiscoverRequest"},"DiscoverResponse":{"properties":{"discovery":{"anyOf":[{"$ref":"#/components/schemas/NormalizedDiscovery"},{"type":"null"}]},"jwks_reachability":{"type":"string","title":"Jwks Reachability"},"findings":{"items":{"$ref":"#/components/schemas/DiscoveryFinding"},"type":"array","title":"Findings"},"status":{"type":"string","title":"Status"}},"type":"object","required":["discovery","jwks_reachability","findings","status"],"title":"DiscoverResponse"},"DiscoveryFinding":{"properties":{"code":{"type":"string","title":"Code"},"severity":{"type":"string","title":"Severity"},"message":{"type":"string","title":"Message"}},"type":"object","required":["code","severity","message"],"title":"DiscoveryFinding"},"Finding":{"properties":{"code":{"type":"string","title":"Code"},"severity":{"type":"string","title":"Severity"},"message":{"type":"string","title":"Message"},"evidence":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Evidence"},"remediation":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Remediation"}},"type":"object","required":["code","severity","message"],"title":"Finding"},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"HealthResponse":{"properties":{"status":{"type":"string","enum":["ok","degraded","down"],"title":"Status"},"version":{"type":"string","title":"Version"},"uptime_seconds":{"type":"number","title":"Uptime Seconds","description":"Seconds since the FastAPI lifespan started. Reset on every deploy; useful for spotting silent restarts."},"checked_at":{"type":"number","title":"Checked At","description":"Unix timestamp at which this snapshot was computed."},"components":{"additionalProperties":{"$ref":"#/components/schemas/ComponentHealth"},"type":"object","title":"Components"}},"type":"object","required":["status","version","uptime_seconds","checked_at","components"],"title":"HealthResponse"},"InspectRequest":{"properties":{"token":{"type":"string","minLength":1,"title":"Token"}},"type":"object","required":["token"],"title":"InspectRequest"},"InspectResponse":{"properties":{"decoded":{"$ref":"#/components/schemas/DecodedPayload"},"validated":{"type":"boolean","title":"Validated"},"warning":{"type":"string","title":"Warning"},"suspicious_warnings":{"items":{"type":"string"},"type":"array","title":"Suspicious Warnings"}},"type":"object","required":["decoded","validated","warning"],"title":"InspectResponse"},"JwksRotationFinding":{"properties":{"code":{"type":"string","title":"Code"},"severity":{"type":"string","title":"Severity"},"message":{"type":"string","title":"Message"}},"type":"object","required":["code","severity","message"],"title":"JwksRotationFinding"},"JwksRotationRequest":{"properties":{"previous_jwks":{"$ref":"#/components/schemas/JwksSet"},"current_jwks":{"$ref":"#/components/schemas/JwksSet"},"overlap_policy":{"anyOf":[{"$ref":"#/components/schemas/OverlapPolicy"},{"type":"null"}]},"sample_token":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Sample Token"},"sample_old_token":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Sample Old Token"},"sample_new_token":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Sample New Token"}},"type":"object","required":["previous_jwks","current_jwks"],"title":"JwksRotationRequest"},"JwksRotationResponse":{"properties":{"rotation_state":{"type":"string","enum":["no_change","safe_overlap","overlap","disjoint"],"title":"Rotation State"},"findings":{"items":{"$ref":"#/components/schemas/JwksRotationFinding"},"type":"array","title":"Findings"},"summary":{"type":"string","title":"Summary"}},"type":"object","required":["rotation_state","findings","summary"],"title":"JwksRotationResponse"},"JwksSet":{"properties":{"keys":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Keys"}},"type":"object","required":["keys"],"title":"JwksSet"},"NormalizedDiscovery":{"properties":{"issuer":{"type":"string","title":"Issuer"},"jwks_uri":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Jwks Uri"},"authorization_endpoint":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization Endpoint"},"token_endpoint":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Token Endpoint"},"supported_algs":{"items":{"type":"string"},"type":"array","title":"Supported Algs"}},"type":"object","required":["issuer","jwks_uri","authorization_endpoint","token_endpoint","supported_algs"],"title":"NormalizedDiscovery"},"OidcAlgPolicy":{"properties":{"allowed_algs":{"items":{"type":"string"},"type":"array","title":"Allowed Algs"}},"type":"object","required":["allowed_algs"],"title":"OidcAlgPolicy"},"OidcLintFinding":{"properties":{"code":{"type":"string","title":"Code"},"severity":{"type":"string","title":"Severity"},"message":{"type":"string","title":"Message"},"evidence":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Evidence"},"remediation":{"type":"string","title":"Remediation"}},"type":"object","required":["code","severity","message","remediation"],"title":"OidcLintFinding"},"OidcLintRequest":{"properties":{"issuer":{"type":"string","minLength":1,"title":"Issuer"},"client_id":{"type":"string","title":"Client Id"},"audiences":{"items":{"type":"string"},"type":"array","title":"Audiences"},"jwks_uri":{"type":"string","minLength":1,"title":"Jwks Uri"},"redirect_uris":{"items":{"type":"string"},"type":"array","title":"Redirect Uris"},"alg_policy":{"$ref":"#/components/schemas/OidcAlgPolicy"},"discovered_jwks_uri":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Discovered Jwks Uri"},"https_required":{"type":"boolean","title":"Https Required","default":true}},"type":"object","required":["issuer","client_id","audiences","jwks_uri","redirect_uris","alg_policy"],"title":"OidcLintRequest"},"OidcLintResponse":{"properties":{"valid":{"type":"boolean","title":"Valid"},"findings":{"items":{"$ref":"#/components/schemas/OidcLintFinding"},"type":"array","title":"Findings"},"summary":{"type":"string","title":"Summary"}},"type":"object","required":["valid","findings","summary"],"title":"OidcLintResponse"},"OverlapPolicy":{"properties":{"min_overlap_count":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Min Overlap Count"},"max_token_ttl_seconds":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Max Token Ttl Seconds"}},"type":"object","title":"OverlapPolicy"},"PresetPolicyTemplate":{"properties":{"allowed_algs":{"items":{"type":"string"},"type":"array","title":"Allowed Algs"},"audiences":{"items":{"type":"string"},"type":"array","title":"Audiences"},"required_claims":{"items":{"type":"string"},"type":"array","title":"Required Claims"},"clock_skew_seconds":{"type":"integer","title":"Clock Skew Seconds"},"secret":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Secret"},"public_key":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Public Key"}},"type":"object","required":["allowed_algs","audiences","required_claims","clock_skew_seconds"],"title":"PresetPolicyTemplate"},"ProviderPresetTemplate":{"properties":{"provider":{"type":"string","title":"Provider"},"issuer":{"type":"string","title":"Issuer"},"policy":{"$ref":"#/components/schemas/PresetPolicyTemplate"},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes"}},"type":"object","required":["provider","issuer","policy"],"title":"ProviderPresetTemplate"},"RegressionCheck":{"properties":{"token":{"type":"string","minLength":1,"title":"Token"},"policy":{"anyOf":[{"$ref":"#/components/schemas/VerifyPolicy"},{"type":"null"}]},"issuer_profile_id":{"anyOf":[{"type":"string","minLength":1},{"type":"null"}],"title":"Issuer Profile Id"},"expected_failure_codes":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Expected Failure Codes"}},"type":"object","required":["token"],"title":"RegressionCheck"},"Statuses":{"properties":{"signature":{"type":"string","title":"Signature"},"issuer":{"type":"string","title":"Issuer"},"audience":{"type":"string","title":"Audience"},"algorithm":{"type":"string","title":"Algorithm"},"time":{"type":"string","title":"Time"},"required_claims":{"type":"string","title":"Required Claims"}},"type":"object","required":["signature","issuer","audience","algorithm","time","required_claims"],"title":"Statuses"},"ValidateRequest":{"properties":{"token":{"type":"string","minLength":1,"title":"Token"},"policy":{"anyOf":[{"$ref":"#/components/schemas/VerifyPolicy"},{"type":"null"}]},"issuer_profile_id":{"anyOf":[{"type":"string","minLength":1},{"type":"null"}],"title":"Issuer Profile Id"}},"type":"object","required":["token"],"title":"ValidateRequest"},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"},"input":{"title":"Input"},"ctx":{"type":"object","title":"Context"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"},"VerifyPolicy":{"properties":{"secret":{"anyOf":[{"type":"string","minLength":1},{"type":"null"}],"title":"Secret"},"public_key":{"anyOf":[{"type":"string","minLength":1},{"type":"null"}],"title":"Public Key"},"issuer":{"type":"string","title":"Issuer"},"audiences":{"items":{"type":"string"},"type":"array","title":"Audiences"},"allowed_algs":{"items":{"type":"string"},"type":"array","title":"Allowed Algs"},"required_claims":{"items":{"type":"string"},"type":"array","title":"Required Claims"},"required_scopes":{"items":{"type":"string"},"type":"array","title":"Required Scopes"},"required_custom_claims":{"additionalProperties":true,"type":"object","title":"Required Custom Claims"},"max_ttl_seconds":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Max Ttl Seconds"},"clock_skew_seconds":{"type":"integer","title":"Clock Skew Seconds","default":0},"token_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Token Type"}},"type":"object","required":["issuer","audiences","allowed_algs"],"title":"VerifyPolicy"},"VerifyResult":{"properties":{"valid":{"type":"boolean","title":"Valid"},"statuses":{"$ref":"#/components/schemas/Statuses"},"findings":{"items":{"$ref":"#/components/schemas/Finding"},"type":"array","title":"Findings"},"summary":{"type":"string","title":"Summary"},"claim_diff":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Claim Diff"},"metadata":{"additionalProperties":true,"type":"object","title":"Metadata"}},"type":"object","required":["valid","statuses","findings","summary"],"title":"VerifyResult"}}}}