Eternaltwin

Home

Oauth

Eternaltwin uses the OAuth 2.0 authorization framework to expose its data to the game websites. Each game website is an OAuth 2 client.

Client creation

The first step is to create an OAuth client. It is not exposed publicly yet.

The creation options are:

  • General information: display name, homepage URI
  • Technical: OAuth redirect (callback) URI

The server creates the application and picks a random secret. The secret is returned as clear-text in the creation response, it is never returned again. The server treats the secret as a password and only stores its hash.

Authorization request

To authenticate a user, the client must redirect the end user to Eternaltwin to request its authorization.

The base URI is https://eternaltwin.org/oauth/authorize, with the following query parameters:

NameDescription
client_idRequired. Client ID received during the client creation
redirect_uriRedirection URI. The default and only accepted value is the one configured during the app creation
loginNot yet implement: username to use by default
scopeNot yet implement: scopes to request
stateA string returned as-is
methodAuthentication method suggestion if the user needs to sign-in (etwin, twinoid, hammerfest). Default: etwin

Parameters

State

The state parameter is a string returned as-is once the user has authenticated. It must include an unguessable part to prevent CSRF attacks.

For the system clients, we use a JWT based on this RFC draft for the state. In particular, it has a "Request Forgery Protection" (rfp) field.

Redirect URI

Eternaltwin does not allow dynamic redirect URIs. Use the state parameter to encode state.

For the system clients, we use https://<game>/oauth/callback if the client supports only one authorization server (Eternaltwin), or https://<game>/oauth/callback/<as> where as is a string identifying the authorization server.

Access token request

Once the user is redirected back to the client callback, the client exchanges the authorization code for an access token with POST https://eternaltwin.org/oauth/token, authenticating itself with its client id and secret.

Authorization codes are valid for 10 minutes.

Errors

Errors are not reported in the RFC 6749 format: there is no error / error_description pair. Eternaltwin replies with an HTTP error status and its own JSON error object:

{"code": "Q1012", "message": "the user has not accepted the terms of service", "extra": null}

A generic OAuth library only reports the HTTP status for these; read the code field to tell them apart. The Node client exposes them as ErrorCode (@eternaltwin/client-node), and RfcOauthClient#getAccessToken (@eternaltwin/oauth-client-http) parses the body into GetAccessTokenError#eternaltwin.

CodeStatusMeaning
Q0002401Missing or invalid client authentication
Q1008422Missing code parameter
Q1010422Malformed authorization code
Q1011422Expired (or not yet valid) authorization code
Q1009403The code was issued for a different client
Q1012403The user has not accepted the terms of service
S0000500Internal error

Terms of service (Q1012)

A user who has not accepted the Eternaltwin terms of service can not take part in an OAuth grant. /oauth/authorize redirects such a user to the acceptance page and comes back to the authorization request once they accept, so a browser flow normally never reaches this error. It is still returned by /oauth/token for codes obtained some other way (a code issued before the user's acceptance was revoked, a non-browser flow, a replayed code).

Clients receiving Q1012 should:

  • treat it as final and user-actionable, not transient: do not retry automatically. The code stays claimable for the rest of its 10 minutes, but retrying is pointless until the user acts.
  • abort the sign-in without creating a local account or session: there is no access token, hence no identity.
  • tell the user their Eternaltwin account must accept the terms of service, link them to https://eternaltwin.org/tos-accept, and offer to restart the flow at /oauth/authorize.

Access tokens issued before this check existed are unaffected: acceptance is only verified when a token is granted, never when it is used.