Discovery

✓ S101 Profile URL is valid and can be fetched Fetched with HTTP 200.
✓ S102 Advertises indieauth-metadata Found https://turner.enemyterritory.org/.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://turner.enemyterritory.org
✓ S106 Authorization endpoint is listed authorization_endpoint is https://turner.enemyterritory.org/selfauth/index
✓ S107 Token endpoint is listed token_endpoint is https://turner.enemyterritory.org/selfauth/token?action=authorize
✓ S108 Introspection endpoint is listed introspection_endpoint is https://turner.enemyterritory.org/selfauth/token?action=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 is missing or is not a list of strings.
✓ 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 Served at https://turner.enemyterritory.org/.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 There was no way to cancel the request.
– S208 Refuses an unregistered cross-origin redirect URI Inconclusive: you reported something other than the expected outcomes.
✗ S209 Accepts a registered cross-origin redirect URI There was no way to cancel the request.
– S210 Matches redirect URIs exactly Inconclusive: you reported something other than the expected outcomes.
– S211 Is not fooled by credentials in a URL Inconclusive: you reported something other than the expected outcomes.
– S212 Ignores client metadata for a different client_id Inconclusive: you reported something other than the expected outcomes.
– S213 Rejects a repeated redirect_uri parameter Inconclusive: you reported something other than the expected outcomes.
✓ 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 approval screen for this request instead of refusing it.
! 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 refused the request.
! S221 Refuses a PKCE method without a challenge Your server showed an approval screen for this request instead of refusing it.
! S222 Refuses a challenge without a method Your server showed an approval screen for this request instead of refusing it.

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 Tokens were issued for a code_verifier that does not match the challenge.
✗ S311 Refuses a missing code_verifier The code was accepted: HTTP 200.
✓ S312 Refuses a code presented by another client Refused (HTTP 400).
✓ S313 Refuses a mismatched redirect_uri Refused (HTTP 400).
✗ S320 Exchanges a code without a scope An access token was issued for a code without any scope.
! S330 Refuses an unknown code Refused, but with HTTP 400 instead of HTTP 400 invalid_grant.
! S331 Refuses missing or unsupported grant types Refused, but with HTTP 400 and HTTP 400.
✗ S332 Errors are JSON with an error code Some error responses were not JSON objects with an "error" member.
✓ S333 Token endpoint refuses GET requests GET requests are refused (HTTP 401).
✓ 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://turner.enemyterritory.org/user/carrvo/index
✓ S405 The returned me is verified me matches a URL seen during discovery.
✗ 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 "profile".
✓ 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 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 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

– S601 Revokes an access token No revocation endpoint.
– S602 Revoked tokens stop working No revocation endpoint.
– S603 Revokes a refresh token No revocation endpoint.
– S604 Revoking an unknown token succeeds No revocation endpoint.

Userinfo

– S701 Returns profile information No userinfo endpoint.
– S702 Refuses a request without a token No userinfo endpoint.
– S703 Refuses an invalid token No userinfo endpoint.

Introspection

✗ S801 Introspection requires authorization Unauthenticated introspection returned HTTP 200 instead of HTTP 401.
✗ S802 Refused introspection reveals nothing Without authorization, the response still revealed that the token is active or whose it is.

Security hygiene

✓ S901 Token endpoint requires TLS Plain http requests are not processed (HTTP 403).
! 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.