The challenger service validates that a user is able to receive challenges at an address (such as e-mail or SMS) and allows an OAuth 2.0 client to obtain access to these validated addresses.
The high-level flow is that an OAuth 2.0 client is first registered with the challenger service (via command-line). Using the command-line tool will print the resulting client ID to the console.
Note
The current service mandates that redirection URIs start with “http://” or “https://”. See issue #7838 for what should be done to lift this restriction.
Note
Right now, registration of a unique redirection URI is mandatory for each client. If multiple redirection URIs are needed, it is suggested to just register additional clients. (While OAuth 2.0 would support not registering fixed redirection URIs with a client, this is not recommended as it would create an open redirector.)
Once a client is registered, that client can use the challenger service when
it needs a user to prove that the user is able to receive messages at a
particular address. However, asking a user to prove access to a particular
address can be expensive as it may involve sending an SMS or even postal mail
depending on the type of address. Thus, challenger does not allow a user
agent to begin an address validation process without prior approval by a
registered client. Thus, the process begins with a /setup
request where a
client requests challenger to begin an address validation request. The
/setup
response contains a nonce
which is then used to construct the
URL of the endpoint to which the client must redirect the user-agent to begin
the address validation and authorization process.
The client then redirects the user-agent to the /authorize/$NONCE
endpoint
of the challenger service, adding its state
, client_id
and
redirect_uri
as query parameters. The redirect_uri
must match the
redirect URI registered with the client. From this endpoint, the challenger
service will return a Web page asking the user to provide its address.
Note
Challenger is a bit unusual in that the
$NONCE
in the endpoint URL makes the authorization endpoint URL (deliberately) unpredictable, while for many other OAuth 2.0 APIs this endpoint is static. However, this is compliant with OAuth 2.0 as determining the authorization URL is left out of the scope of the standard.
When the user has filled in the form with their address, it will be submitted
to the /challenge/$NONCE
endpoint and the challenger service will send a
challenge to the user’s address and generate an HTML form asking the user to
enter the received challenge value.
The user can then enter the answer to the challenge which is then submitted to
the /solve/$NONCE
endpoint. If the answer is correct, the user agent will
be redirected to the client redirect URI that was specified by the OAuth 2.0
client upon /authorize
, together with an authorization grant encoded in
the redirection URI.
Given this authorization grant, the OAuth 2.0 client can then use the
/token
endpoint to obtain an access token which will grant it access to
the resource.
Using the /info
endpoint the client can then finally obtain the (now)
verified address of the user.
These APIs allow clients to obtain the terms of service and the privacy policy of a service.
GET
/terms
¶Get the terms of service of the service. The endpoint will consider the “Accept” and “Accept-Language” and “Accept-Encoding” headers when generating a response. Specifically, it will try to find a response with an acceptable mime-type, then pick the version in the most preferred language of the user, and finally apply compression if that is allowed by the client and deemed beneficial.
The endpoint will set an “Etag”, and subsequent requests of the same client should provide the tag in an “If-None-Match” header to detect if the terms of service have changed. If not, a “304 Not Modified” response will be returned. Note that the “304 Not Modified” will also be returned if the client changed the “Accept-Language” or “Accept-Encoding” header. Thus, if the client would like to download the resource in a different language or format, the “If-None-Match” header must be omitted.
If the “Etag” is missing, the client should not cache the response and instead prompt the user again at the next opportunity. This is usually only the case if the terms of service were not configured correctly.
When returning a full response (not a “304 Not Modified”), the server should also include a “Avail-Languages” header which includes a comma-separated list of the languages in which the terms of service are available in (see availability hints specification). Clients can use this to generate a language switcher for users that may not have expressed a proper language preference.
GET
/privacy
¶Get the privacy policy of the service. Behaves the same way as The “/terms” endpoint, except that it returns the privacy policy instead of the terms of service.
GET
/config
¶Obtain the key configuration settings of the storage service.
Response:
Returns a ChallengerTermsOfServiceResponse.
interface ChallengerTermsOfServiceResponse {
// Name of the service
name: "challenger";
// libtool-style representation of the Challenger protocol version, see
// https://www.gnu.org/software/libtool/manual/html_node/Versioning.html#Versioning
// The format is "current:revision:age".
version: string;
}
POST
/setup/$CLIENT_ID
¶This endpoint is used by the client to authorize the execution of an address
validation on its behalf. An Authorization
header (for now always using
a Bearer
token) should be included to provide the client’s credentials
to authorize access to the challenger service. This token must match the
client_secret
from the registration of the client with the challenger
service (which will also be used in the later /token
request).
Response:
Details::
interface ChallengeSetupResponse {
// Nonce to use when constructing /authorize endpoint.
nonce: string;
}
GET
/authorize/$NONCE
¶POST
/authorize/$NONCE
¶This is the “authorization” endpoint of the OAuth 2.0 protocol. This endpoint is used by the user-agent. It will return a form to enter the address.
Request:
code
Response:
POST
/challenge/$NONCE
¶This endpoint is used by the user-agent to submit the address to which a challenge should be sent by the challenger service.
Request:
Body should use the mime-type “application/x-www-form-urlencoded”. The posted form data must contain an “address”.
Response:
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:
Depends on the form from /challenge
. TBD.
Response:
/authorize
),
plus a code
argument with the authorization code, and the
state
argument from the /authorize
endpoint.POST
/token
¶This is the token endpoint of the OAuth 2.0 specification. This endpoint is used by the client to provide its authorization code, demonstrating that it has the right to learn a particular user’s validated address. In return, the challenger service returns the access token. Renewal is not supported.
Request:
The request must include an application/www-form-urlencoded
body
specifying the client_id
, redirect_uri
, client_secret
, code
and grant_type
. The grant_type
must be set to
authorization_code
. The redirect_uri
must match the URI from
/authorize
. The code
must be the authorization code that /solve
returned to the user. The client_id
and client_secret
must match
the usual client credentials.
Response:
Error responses follow RFC 6749, section 5.2 with an “error” field in JSON, as well as also returning GNU Taler style error messages.
Details::
interface ChallengerAuthResponse {
// Token used to authenticate access in /info.
access_token: string;
// Type of the access token.
token_type: "Bearer";
// Amount of time that an access token is valid (in seconds).
expires_in: Integer;
}
GET
/info
¶This userinfo endpoint of the OAuth 2.0 specification. This endpoint is used by the client to obtain the user’s validated address.
Request:
Must include the token returned to the client from the /token
endpoint
as a Bearer
token in an Authorization
header.
Response:
Details::
interface ChallengerInfoResponse {
// Address that was validated.
address: string;
// Type of the address.
address_type: string;
// How long do we consider the address to be
// valid for this user.
expires: Timestamp;
}