Implementation reports · Server
Indiekit
45 passed 9 failed 12 warnings 15 skipped
Published 2026-09-17 04:31 UTC by https://www.ciccarello.me · tested with https://www.ciccarello.me/ · suite cec87e9
Discovery
| ✓ | S101 | Profile URL is valid and can be fetched Fetched with HTTP 200. |
| ✓ | S102 | Advertises indieauth-metadata Found https://indiekit.ciccarello.me/.well-known/oauth-authorization-server in the HTML. |
| ✓ | S103 | Link header and HTML agree Only one of them is present. |
| ✓ | S104 | Metadata is a JSON document HTTP 200 with a JSON object. |
| ✓ | S105 | Issuer identifier is valid issuer is https://indiekit.ciccarello.me |
| ✓ | S106 | Authorization endpoint is listed authorization_endpoint is https://indiekit.ciccarello.me/auth |
| ✓ | S107 | Token endpoint is listed token_endpoint is https://indiekit.ciccarello.me/auth/token |
| ✓ | S108 | Introspection endpoint is listed introspection_endpoint is https://indiekit.ciccarello.me/auth/introspect |
| ✓ | S109 | PKCE S256 is supported S256 is listed. |
| ! | S110 | Advertises the iss response parameter authorization_response_iss_parameter_supported is not true, so clients cannot rely on iss for mix-up protection. |
| ✓ | S111 | Lists supported scopes scopes_supported lists create, draft, update, delete, media, read, follow, mute, block, channels |
| ✓ | S112 | Response and grant types are consistent Consistent (or using the defaults). |
| – | S113 | Revocation needs no client authentication No revocation_endpoint is listed. |
| ✓ | S114 | Metadata can be read by browser-based apps No CORS headers; browser-based apps cannot read the metadata directly. |
| ✓ | S115 | Legacy endpoint links match the metadata Legacy links match the metadata. |
| ✓ | S116 | Endpoints use https All endpoints use https. |
| · | S117 | Serves metadata at the RFC 8414 well-known URL |
Authorization requests
| ✓ | S201 | Returns state unmodified state was returned unmodified. |
| ✓ | S202 | Returns the iss parameter iss matched the issuer on every redirect. |
| ✓ | S203 | Issues an authorization code A code was issued. |
| ✓ | S204 | Keeps the query string of the redirect URI The query string of the redirect URI was kept. |
| ✓ | S205 | Fetches client information Your server fetched the client_id document. |
| – | S206 | Consent screen identifies the application You skipped this step. |
| ✗ | S207 | Reports a denied request to the client There was no way to cancel the request. |
| ✓ | S208 | Refuses an unregistered cross-origin redirect URI Your server showed an error and did not redirect. |
| ✗ | S209 | Accepts a registered cross-origin redirect URI Your server showed an error for a request it should have allowed. |
| ✓ | S210 | Matches redirect URIs exactly Your server showed an error and did not redirect. |
| ✓ | S211 | Is not fooled by credentials in a URL Your server showed an error and did not redirect. |
| ✓ | S212 | Ignores client metadata for a different client_id Your server showed an error and did not redirect. |
| ! | S213 | Rejects a repeated redirect_uri parameter Your server showed an approval screen for an unregistered redirect URI instead of an error. |
| ✓ | S214 | Is not an open redirector Your server showed an error and did not redirect. |
| ! | S215 | Requires PKCE Your server showed an approval screen for this request instead of refusing it. |
| ! | S216 | Refuses the plain PKCE method Your server showed an approval screen for this request instead of refusing it. |
| ✓ | S217 | Refuses the implicit flow Your server showed an error. |
| ✓ | S218 | Handles a missing state parameter Your server showed an error. |
| ! | S219 | Refuses an invalid client_id Your server showed an approval screen for this request instead of refusing it. |
| ✓ | S220 | Does not trust the me parameter Your server returned https://www.ciccarello.me rather than the profile URL the request asked for. |
| · | S221 | Refuses a PKCE method without a challenge |
| · | S222 | Refuses a challenge without a method |
Code redemption
| ✓ | S301 | Exchanges a code at the token endpoint The code was exchanged for tokens. |
| ✗ | S302 | Codes can only be used once The same code was exchanged a second time. |
| – | S303 | Reusing a code revokes its tokens No userinfo endpoint to check the tokens with. |
| ✓ | S310 | Refuses a wrong code_verifier The wrong verifier was refused (HTTP 401 unauthorized). |
| ✓ | S311 | Refuses a missing code_verifier Refused (HTTP 500 ERR_INVALID_ARG_TYPE). |
| ✓ | S312 | Refuses a code presented by another client Refused (HTTP 401 unauthorized). |
| ✗ | S313 | Refuses a mismatched redirect_uri The code was accepted: HTTP 200. |
| ✓ | S320 | Exchanges a code at the authorization endpoint Returned me (https://www.ciccarello.me) and no access token. |
| ! | S330 | Refuses an unknown code Refused, but with HTTP 401 unauthorized instead of HTTP 400 invalid_grant. |
| ! | S331 | Refuses missing or unsupported grant types Refused, but with HTTP 400 bad_request and HTTP 400 bad_request. |
| ✓ | S332 | Errors are JSON with an error code Error responses are JSON with an error code. |
| ! | S333 | Token endpoint refuses GET requests The token endpoint answered a GET request with HTTP 200. |
| ✓ | S334 | Token endpoint supports CORS preflight No CORS preflight support; browser-based apps cannot call the token endpoint directly. |
Token responses
| ✓ | S401 | Token response is JSON HTTP 200 with a JSON object. |
| ✓ | S402 | Includes an access token An access token was issued. |
| ✓ | S403 | Token type is Bearer token_type is Bearer. |
| ✓ | S404 | Returns a valid me me is https://www.ciccarello.me |
| ✓ | S405 | The returned me is verified https://www.ciccarello.me declares the same authorization endpoint. |
| ✗ | S406 | Token responses are not cached The response does not send Cache-Control: no-store, so tokens could be cached. |
| ! | S407 | Says when the token expires expires_in is missing, so the client cannot tell when the token expires. |
| ! | S408 | Reports the granted scope scope is missing from the response. |
| ✓ | S409 | Profile information is well formed No profile information was returned, which is allowed. |
| ✓ | S410 | Access tokens are hard to guess The access token is long enough. |
| ✓ | S420 | Access token format Access tokens are JWTs, signed with HS256. |
| ! | S421 | JWT header marks it an access token The JWT header says typ "JWT" rather than "at+jwt". |
| ✗ | S422 | JWT verifies against the published keys The metadata has no jwks_uri, so a resource server cannot get the key to verify the token with. |
| ✗ | S423 | JWT claims are complete The claims are not what a resource server needs: missing iss, aud, sub. |
Refresh tokens
| – | S501 | Refreshes an access token No refresh token was issued. |
| – | S502 | Refuses a refresh by another client No refresh token was issued. |
| – | S503 | Refuses to add scopes on refresh No refresh token was issued. |
| – | S504 | Old refresh tokens stop working after rotation No refresh token was issued. |
| – | S505 | Refresh token reuse revokes the grant No refresh token was issued. |
Revocation
Userinfo
Introspection
Security hygiene
| ✓ | S901 | Token endpoint requires TLS Plain http requests are not processed (HTTP 302). |
| ! | S902 | Authorization pages cannot be framed The authorization endpoint does not send X-Frame-Options or CSP frame-ancestors, so it could be framed for clickjacking. |
| ✓ | S905 | Tokens never appear in URLs No tokens appeared in redirect URLs. |
| ✓ | S906 | No credentialed wildcard CORS No credentialed wildcard CORS. |