Implementation reports · Server
Indiko
https://tangled.org/dunkirk.sh/indiko/
81 passed 0 failed 0 warnings 3 skipped
Published 2026-10-28 05:48 UTC by https://dunkirk.sh/ · tested with https://dunkirk.sh/ · suite 9e65154
Discovery
| ✓ | S101 | Profile URL is valid and can be fetched Fetched with HTTP 200. |
| ✓ | S102 | Advertises indieauth-metadata Found https://indiko.dunkirk.sh/.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://indiko.dunkirk.sh |
| ✓ | S106 | Authorization endpoint is listed authorization_endpoint is https://indiko.dunkirk.sh/auth/authorize |
| ✓ | S107 | Token endpoint is listed token_endpoint is https://indiko.dunkirk.sh/auth/token |
| ✓ | S108 | Introspection endpoint is listed introspection_endpoint is https://indiko.dunkirk.sh/auth/token/introspect |
| ✓ | S109 | PKCE S256 is supported S256 is listed. |
| ✓ | S110 | Advertises the iss response parameter authorization_response_iss_parameter_supported is true. |
| ✓ | S111 | Lists supported scopes scopes_supported lists openid, profile, email, offline_access |
| ✓ | S112 | Response and grant types are consistent Consistent (or using the defaults). |
| ✓ | S113 | Revocation needs no client authentication revocation_endpoint_auth_methods_supported is ["none"]. |
| ✓ | S114 | Metadata can be read by browser-based apps Access-Control-Allow-Origin: * |
| ✓ | 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 Served at https://indiko.dunkirk.sh/.well-known/oauth-authorization-server with the same issuer. |
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 The approval screen showed the application name and client_id. |
| ✓ | S207 | Reports a denied request to the client Cancelling returned error=access_denied. |
| ✓ | 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 The registered cross-origin redirect URI was used. |
| ✓ | 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 error and did not redirect. |
| ✓ | S214 | Is not an open redirector Your server showed an error and did not redirect. |
| ✓ | S215 | Requires PKCE Your server refused the request with error=invalid_request. |
| ✓ | S216 | Refuses the plain PKCE method Your server refused the request with error=invalid_request. |
| ✓ | S217 | Refuses the implicit flow Your server refused the request with error=unsupported_response_type. |
| ✓ | S218 | Handles a missing state parameter Your server refused the request with error=invalid_request. |
| ✓ | S219 | Refuses an invalid client_id Your server showed an error. |
| ✓ | S220 | Does not trust the me parameter Your server returned https://dunkirk.sh/ rather than the profile URL the request asked for. |
| ✓ | S221 | Refuses a PKCE method without a challenge Your server refused the request with error=invalid_request. |
| ✓ | S222 | Refuses a challenge without a method Your server refused the request with error=invalid_request. |
Code redemption
| ✓ | S301 | Exchanges a code at the token endpoint The code was exchanged for tokens. |
| ✓ | S302 | Codes can only be used once The used code was refused (HTTP 400 invalid_grant). |
| ✓ | S303 | Reusing a code revokes its tokens The tokens issued for the code were revoked when it was replayed. |
| ✓ | S310 | Refuses a wrong code_verifier The wrong verifier was refused (HTTP 400 invalid_grant). |
| ✓ | S311 | Refuses a missing code_verifier Refused (HTTP 400 invalid_request). |
| ✓ | S312 | Refuses a code presented by another client Refused (HTTP 400 invalid_grant). |
| ✓ | S313 | Refuses a mismatched redirect_uri Refused (HTTP 400 invalid_grant). |
| ✓ | S320 | Exchanges a code without a scope Returned me (https://dunkirk.sh/) and no access token. |
| ✓ | S330 | Refuses an unknown code Refused with HTTP 400 invalid_grant. |
| ✓ | S331 | Refuses missing or unsupported grant types Refused with invalid_request and unsupported_grant_type. |
| ✓ | S332 | Errors are JSON with an error code Error responses are JSON with an error code. |
| ✓ | S333 | Token endpoint refuses GET requests GET requests are refused (HTTP 405 invalid_request). |
| ✓ | S334 | Token endpoint supports CORS preflight Preflight allowed for *. |
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://dunkirk.sh/ |
| ✓ | S405 | The returned me is verified me matches a URL seen during discovery. |
| ✓ | S406 | Token responses are not cached Cache-Control: no-store is set. |
| ✓ | S407 | Says when the token expires expires_in is 3600 seconds. |
| ✓ | S408 | Reports the granted scope scope is "profile". |
| ✓ | S409 | Profile information is well formed The profile object is well formed. |
| ✓ | S410 | Access tokens are hard to guess The access token is long enough. |
| ✓ | S420 | Access token format Access tokens are opaque strings, which resource servers check by introspection. |
| – | S421 | JWT header marks it an access token The access token is not a JWT. |
| – | S422 | JWT verifies against the published keys The access token is not a JWT. |
| – | S423 | JWT claims are complete The access token is not a JWT. |
Refresh tokens
| ✓ | S501 | Refreshes an access token Refreshing returned a new access token. |
| ✓ | S502 | Refuses a refresh by another client Refused for a different client_id (HTTP 400 invalid_grant). |
| ✓ | S503 | Refuses to add scopes on refresh Asking for more scope was refused (HTTP 400 invalid_scope). |
| ✓ | S504 | Old refresh tokens stop working after rotation The replaced refresh token was refused (HTTP 400 invalid_grant). |
| ✓ | S505 | Refresh token reuse revokes the grant Reusing the old refresh token revoked the newest tokens too. |
Revocation
Userinfo
Introspection
Security hygiene
| ✓ | S901 | Token endpoint requires TLS Plain http requests are not processed (HTTP 301). |
| ✓ | S902 | Authorization pages cannot be framed Framing is prevented (X-Frame-Options: DENY). |
| ✓ | S905 | Tokens never appear in URLs No tokens appeared in redirect URLs. |
| ✓ | S906 | No credentialed wildcard CORS No credentialed wildcard CORS. |