Contents

POST /solve/$NONCE#

Used by the user-agent to submit an answer to the challenge. If the answer is correct, the user will be redirected to the client’s redirect URI, otherwise the user may be given another chance to complete the process.

Request:

Body should use the mime-type “application/x-www-form-urlencoded”; multipart/form-data is accepted as well. The posted form data must contain a “pin” field, whose value must be a decimal unsigned integer. The request body is limited to 1024 bytes.

Response:

200 OK:

If the request ask for application/json the response is a ChallengeSolveResponse. Since protocol v2. Note that this status is only used for the successful outcome; an incorrect or unusable TAN is reported with 403, 409 or 429 (see below).

302 Found:

Only possible if request didn’t ask for application/json. Since protocol v2. The user is redirected to the redirect URI of the client to pass the grant to the client. The target will be the redirect URI specified by the client (during registration and again upon /authorize), plus a code argument with the authorization code, and the state argument from the /authorize endpoint. The state argument is omitted entirely if the client did not supply one. The response body is the plain text Ok!.

400 Bad Request:

The request does not follow the spec. Since protocol v1. Error codes used are:

  • TALER_EC_GENERIC_PARAMETER_MALFORMED — the $NONCE in the URL is not a valid 52-character Crockford-base32 value (detail is "nonce"), the Content-Length header is not a number (detail is "Content-Length"), or the pin field is not a decimal number (detail is "pin").

  • TALER_EC_GENERIC_PARAMETER_MISSING — there is no pin field in the body (detail is "pin").

403 Forbidden:

The TAN was checked and did not match. The response is InvalidPinResponse. Since protocol v1. Returned with TALER_EC_CHALLENGER_INVALID_PIN.

404 Not found:

The service is unaware of a matching challenge, or the validation has expired. Since protocol v1. Returned with TALER_EC_CHALLENGER_GENERIC_VALIDATION_UNKNOWN.

405 Method Not Allowed:

The request used a method other than POST or OPTIONS. Returned by the request router with an Allow header and an empty body; in particular there is no Taler error code.

409 Conflict:

The service had never actually transmitted a TAN, so solving is naturally impossible. Since protocol v8. The response is an InvalidPinResponse with no_challenge set to true. Returned with TALER_EC_CHALLENGER_NO_CHALLENGE_TRANSMITTED.

413 Request entity too large:

The request body exceeds the 1024 byte limit. Returned with TALER_EC_GENERIC_UPLOAD_EXCEEDS_LIMIT.

415 Unsupported Media Type:

The Content-Type is missing or is not one the service can parse. Returned with TALER_EC_GENERIC_PARAMETER_MALFORMED and detail set to "Content-Type". Since protocol v8; previously reported as 400.

429 Too Many Requests:

There have been too many attempts to solve the challenge for this address (and $NONCE). The user-agent should either try a different address (or wait and (eventually) request a fresh nonce to be set up by the client). Since protocol v2. The body is an InvalidPinResponse in both of the cases below, which are told apart by the error code:

  • TALER_EC_CHALLENGER_NO_PIN_ATTEMPTS_LEFT — the user has run out of TAN guesses but may still request a retransmission or change the address. exhausted is true. Since protocol v8.

  • TALER_EC_CHALLENGER_TOO_MANY_ATTEMPTS — the user has exhausted address changes, TAN guesses and retransmissions, so the situation is terminal and all three counters are zero. Since protocol v8 this returns an InvalidPinResponse as well; it previously returned a plain error object with only code, hint and detail. Note that the response consuming the very last guess already reports this, rather than TALER_EC_CHALLENGER_INVALID_PIN with a 403: at that point nothing is left to try, which is the more useful thing to tell the user.

500 Internal Server Error:

Server is not able to respond due to internal problems. Since protocol v1. Returned with TALER_EC_GENERIC_DB_FETCH_FAILED; detail is "do_solve_challenge" when solving failed and "get_validation" when the subsequent construction of the redirect URL failed.

Note

Error responses are always JSON, even when the request asked for text/html; only the success case honours the Accept header by returning a 302 redirect.

Note

Once a challenge has been solved, repeating the request for the same (unexpired) $NONCE succeeds again regardless of the pin submitted, re-issuing the redirect and authorization code.

// Only the "completed" variant occurs with a 200 status; the
// "pending" variant (InvalidPinResponse) is returned with a 403,
// 409 or 429 status.  Since **v8** every unsuccessful /solve uses
// that one shape, so a client need only parse InvalidPinResponse.
type ChallengeSolveResponse = ChallengeRedirect;
interface InvalidPinResponse {
  // Union discriminator field.
  type: "pending";

  // numeric Taler error code, should be shown to indicate the error
  // compactly for reporting to developers
  code: Integer;

  // human-readable Taler error code, should be shown for the user to
  // understand the error
  hint: string;

  // how many times is the user still allowed to change the address;
  // if 0, the user should not be shown a link to jump to the
  // address entry form
  addresses_left: Integer;

  // how many times might the TAN still be retransmitted
  pin_transmissions_left: Integer;

  // how many times might the user still try entering the TAN code
  auth_attempts_left: Integer;

  // if true, the TAN was not even evaluated as the user previously
  // exhausted the number of attempts
  exhausted: boolean;

  // if true, the TAN was not even evaluated as no challenge was ever
  // issued (the user must have skipped the step of providing their
  // address first!)
  no_challenge: boolean;
}