Skip to content

Instantly share code, notes, and snippets.

@shilga
Last active December 21, 2018 11:05
Show Gist options
  • Save shilga/ca58dac6f86a71bf27600b88605dd06c to your computer and use it in GitHub Desktop.
Save shilga/ca58dac6f86a71bf27600b88605dd06c to your computer and use it in GitHub Desktop.
Frontier OAuth2 authentication API investigation
With the new Chapter 4 Elite Dangerous update Frontier implemented for the companion API a new authentication mechanism. The mechanism is based on OAuth2. To get general infos about how OAauth works the following links a good readings:
- https://aaronparecki.com/oauth-2-simplified/
- https://www.digitalocean.com/community/tutorials/an-introduction-to-oauth-2
The new mechanism can be tested for example with the tool Postman:
1) Open https://companion.orerve.net/login (Frontier provided this demo web-app)
2) website redirects to https://auth.frontierstore.net/auth?state={random_state}&response_type=code&approval_prompt=auto&redirect_uri=https%3A%2F%2Fcompanion.orerve.net%2Flogin&client_id=4e135d0a-e313-4ace-b76b-22947d1be13e I replaced the state with {random_state} as it should change with each call
3) Login in with the Frontier credentials and grant access to "Companion"
4) Web Auth redirects to https://companion.orerve.net/login?code={auth_request_code}&state={random_state} . The webservice behind this example application finishes the authentication by requesting the access_token and printing it. This part is still magic, as we can't see what is happening behind the scenes
5) Copy the printed access_token and create a new request with Postman: GET-Request to https://companion.orerve.net/market and put in an header 'x-frontier-auth' with the copied access_token as value. The API will return market prices of the station you are docked in
In order to use this in an own tool or webservice an own client_id and client_secret has to be created. This can be done on https://auth.frontierstore.net/ Login there with your Frontier credentials. Click on the link at the bottom 'developer apps'. Then on 'Register an App'. Put in some information and create the info. You can retrieve client_id and client_secret from there.
In order to integrate OAuth2 in to your application you have to redirect users to https://auth.frontierstore.net/auth?state={random_state}&response_type=code&approval_prompt=auto&redirect_uri={url_encoded_redirect_uri}&client_id={client_id}. Replace the state with some random generated text, replace {client_id} with your id from registration of your application. Fill in the redirect_uri. This is the URL the user is redirected as a callback for you application if the user accepted the authentication or not. You can use localhost (eg http://localhost/login http%3A%2F%2Flocalhost%2Flogin ) if you are using a standalone application like the Market Connector. The app must of course implement a webserver then.
From now on it is speculation. After the user has authorized the login and you got the callback you have to request the auth_token from the API based on the code you get with the callback. First check the state parameter to know which for which user the callback was called now. On an web application several authentications could run at the same time.
Create a POST request to https://auth.frontierstore.net/token
Put in the following values in x-www-form-urlencoded and set this application type in the request header:
- grant_type: authorization_code
- code: {code_from_callback}
- client_id: {your_client_id}
- client_secert: {your_client_secret}
- state: {your_random_state_text}
- redirect_uri: {the callback uri you used}
It returns with a JSON like this:
{
"access_token": "eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkExMjhDQkMtSFMyNTYiLCJ6aXAiOiJERUYifQ.0.............",
"token_type": "Bearer",
"expires_in": 14376,
"refresh_token": "1c7d5ea1-648c-4ff0-ba10-8b78de09d033"
}
Retreive the tokens. Use the access_token to use the Companion API.
After the token has expired a new one can be retreived with the refresh_token. For that create POST-request https://auth.frontierstore.net/token. Put in the following values again x-www-form-urlencoded:
- grant_type: refresh_token
- client_id: {your_client_id}
- client_secert: {your_client_secret}
- refresh_token: {refresh_token from last auth response}
You will again receive a JSON auth response, which contains again access_token and refresh_token.
@jimkeir
Copy link

jimkeir commented Dec 21, 2018

Frontier added some basic info on the authentication process at http://hosting.zaonce.net/docs/oauth2/instructions.html . I can confirm that the PKSE method (sending a code_challenge) works without having to have a local webserver, as long as you're using an in-process browser and can read the URL returned after the auth. This from EVA (Java/Android):

redirectUri = "EVA://authCallback";
sessionState = UUID.randomUUID().toString();
String url = "https://auth.frontierstore.net/auth?response_type=code&redirect_uri=" +
           URLEncoder.encode(redirectUri, "UTF-8") + "&client_id=" + clientKey;

// Needs to be a minimum of 43 chars apparently, so use two UUIDs. Should already be URL-safe.
codeVerifier = UUID.randomUUID().toString() + UUID.randomUUID().toString();

MessageDigest digest = MessageDigest.getInstance("SHA-256");
byte[] hash = digest.digest(codeVerifier.getBytes(StandardCharsets.UTF_8));
String codeChallenge = Base64.encodeToString(hash, Base64.NO_WRAP)
		.replace('+','-')
		.replace('/','_')
		.replace("=","");
url += "&code_challenge=" + codeChallenge + "&code_challenge_method=S256";
url += "&state=" + URLEncoder.encode(sessionState, "UTF-8");
url += "&scope=openid";

... Open this URL in a browser window and capture the redirected URL ...

authCode = uri.getQueryParameter("code");
HttpURLConnection oauthConnection = (HttpURLConnection) new URL("https://auth.frontierstore.net/token").openConnection();
oauthConnection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
oauthConnection.setRequestProperty("Accept", "application/json");
oauthConnection.setRequestMethod("POST");
String postData = "grant_type=authorization_code&client_id=" + clientKey +
       "&redirect_uri=" + URLEncoder.encode(redirectUri, "UTF-8") + "&code=" + authCode + "&code_verifier=" + codeVerifier;

Post the data to the URL and get back the standard OAuth2 response.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment