# Starter Specifications
# Overview
This article aims to provide technical guidance for initiators to implement the authlib-injector specification. Since this function needs to call the Yggdrasil API, it is recommended that you read the [Yggdrasil Server Technical Specification] (Yggdrasil-Server Technical Specification) before reading this article.
In the launcher, this login method can be called [external login (authlib-injector)] or [authlib-injector login]. We recommend that you use the former, which is more explicit.
# verify server
The authentication server (i.e. the Yggdrasil server) is the core of the whole authentication system, and all authentication related requests will be sent to it.
In order to determine an authentication server, the initiator should store the API address of the authentication server (i.e. API Root, e.g. https://example.com/api/yggdrasil/
).
An initiator can support only one authentication server or multiple authentication servers. Supporting multiple authentication servers means that multiple accounts can exist in the launcher at the same time, and these accounts can belong to different authentication servers.
# Verify server settings
The operation of setting up the verification server is generally done by the player, but there are also cases where the server owner performs the setting, and the configuration file is distributed together with the launcher and the game. Here are a few ways to set up an authentication server:
# Specify in the configuration file
The initiator can store the API address directly in the configuration file, allowing users to set the authentication server by modifying the configuration file. This configuration method is simple to implement. If your launcher is only used as a server-only launcher, you can use this configuration method.
# Enter the address in the launcher
In this configuration, the user completes the authentication server setup by entering the URL in the launcher. The URL here may be the full API address (such as https://example.com/api/yggdrasil/
), or it may be an abbreviated address (such as example.com
).
When the URL does not indicate a protocol (HTTPS or HTTP), we agree to autocomplete it to the HTTPS protocol. That is, example.com/api/yggdrasil/
should be read as https://example.com/api/yggdrasil/
.
For security reasons, an initiator MUST NOT downgrade to the clear-text HTTP protocol even if it cannot connect via the HTTPS protocol.
Meanwhile, authlib-injector specifies a service discovery mechanism called API Address Indication (ALI). It is used to convert an abbreviated, incomplete address entered by the user into a full API address.
# Handling API Address Indication (ALI)
In order to resolve the address entered by the user to the real API address, the initiator needs to do the following:
- If the URL is missing a protocol, complete it with the HTTPS protocol.
- Send a GET request to the URL (following an HTTP redirect).
- If the response contains an ALI header (HTTP header
X-Authlib-Injector-API-Location
), then the URL pointed to by the ALI is the API address.X-Authlib-Injector-API-Location
can be an absolute URL or a relative URL.- If the ALI points to itself, that means the current URL is the API address.
- If the response does not contain an ALI header, the current URL is assumed to be the API address by default.
The pseudo-code:
function resolve_api_url(url)
response = http_get(url) // follow redirects
if response.headers["x-authlib-injector-api-location"] exists
new_url = to_absolute_url(response.headers["x-authlib-injector-api-location"])
if new_url != url
return new_url
// if you are going to fetch the metadata next, 'response' can be reused
return url
# Setting by drag and drop
This method allows the user to set the authentication server through Mouse Drag (DnD) (opens new window).
The DnD source can be a browser or other application, and the DnD target is the launcher. The DnD source needs to display a piece of text, image, or other content, instructing the user to drag this content into the launcher to add an authentication server. During this process, the verification server information is transferred from the DnD source to the initiator. After completing the DnD action, the initiator confirms to the user whether to add this authentication server.
# Drag data
The MIME type of the drag data is text/plain
, and the content is a URI in the following format:
authlib-injector:yggdrasil-server:{authentication server API address}
where the API address is a component of a URI and should be encoded (opens new window).
The drag effect is a copy (copy
).
# HTML example
Add draggable="true"
to the DOM node that needs to be dragged, and handle the dragstart
event:
<span id="dndLabel" draggable="true" ondragstart="dndLabel_dragstart(event);">example.yggdrasil.yushi.moe</span>
function dndLabel_dragstart(event) {
let yggdrasilApiRoot = "https://example.yggdrasil.yushi.moe/";
let uri = "authlib-injector:yggdrasil-server:" + encodeURIComponent(yggdrasilApiRoot);
event.dataTransfer.setData("text/plain", uri);
event.dataTransfer.dropEffect = "copy";
}
# Verify the rendering of server information
By sending a GET request to the API address, the initiator can get the metadata of the authentication server ([response format](Yggdrasil-server-specific specification#api-metadata-get)), such as the server name. The launcher can use this metadata to improve the user experience.
# Display of server name
The authentication server specifies the name of the authentication server in serverName
in meta
. This name can be used when the initiator needs to present an authentication server to the user.
Note that authentication server names may conflict, so the initiator should provide a way to view the authentication server API address. For example, when the mouse hovers over the authentication server name, the launcher displays its API address in the Tooltip.
# Warning for non-HTTPS authenticated servers
When a user attempts to set up an authentication server using the cleartext HTTP protocol, the initiator should display a prominent warning to the user that this may put the security of their information at risk and that the user's password will be transmitted in cleartext.
# account
An account corresponds to a player in the game, and the user can select an account to play the game at startup.
Relationship between accounts, users and roles: The concept of accounts in the launcher is not the same as the concept of users in the authentication server. Corresponding to the account in the launcher is the role (Profile) in the authentication server. The user in the authentication server is the owner of one or more roles, which has no corresponding entity in the launcher.
# Storage of account information
The initiator identifies an account by the following three immutable properties:
- The authentication server to which the account belongs
- The ID of the account (eg email address)
- Usually the account ID is the mailbox. However, if the
feature.non_email_login
field in the metadata returned by the authentication server is true, it means that the authentication server supports logging in with credentials other than the mailbox, that is, the account ID may not be the mailbox. At this point, the launcher should not expect that the account entered by the user must be a mailbox, and pay attention to the wording (such as using the word "account" instead of the word "mailbox") to avoid confusion. (For details, please refer to [Yggdrasil Server Technical Specification § Login with Role Name](Yggdrasil-Server Technical Specification #Login with Role Name))
- Usually the account ID is the mailbox. However, if the
- UUID of the role corresponding to the account
Two accounts are the same only if the above three attributes of the two accounts are the same, and the same attribute does not mean that the two accounts are the same. Multiple roles can exist on the same authentication server; multiple roles can belong to the same user; roles with the same UUID can also appear on different authentication servers. Therefore, the initiator should use all three attributes to identify the account.
In addition to the above three attributes, an account has the following attributes:
- Tokens (accessToken and clientToken)
- The name of the role corresponding to the account
- User's ID
- User properties
Safety Warning:
- Remember that the login status record is the token, not the user's password. Passwords SHOULD NOT be stored in clear text at any time.
The above properties are all mutable. After every login or refresh operation, the launcher needs to update the stored account properties.
In all login and refresh operations below, the requestUser
parameter in the request is true
, so that the enabler can update the user ID and user attributes on the fly.
# Add account
If the user wants to add an account, the launcher needs to ask the authentication server the user is using, the user's account and password. The authentication server here can be preset, selected by the user from the list of authentication servers, or set by the user on-the-fly ([see above](#authentication server settings)).
After this, the launcher does the following:
- Call the [login interface] of the corresponding authentication server (Yggdrasil-Server Technical Specification #Login), which contains the account and password entered by the user.
- If the
selectedProfile
in the response is not empty, the login is successful, and the account properties are updated with the information in the response. Process ends. - If the
availableProfiles
in the response is empty, the user does not have any role, and an exception is triggered. - The user is prompted to select a role from
availableProfiles
. - Call [Refresh Interface] (Yggdrasil-Server Technical Specification #Refresh), where the token is the token returned by the login operation, and
selectedProfile
is the role selected by the user in the previous step. - The login is successful, and the account properties are updated with the information in the refresh response.
# Confirmation of credential validity
Before the launcher can use the credential (for example, before launching the game), it needs to confirm its validity. If the credentials are invalid, the user is required to log in again. The steps to confirm the validity of the credentials are as follows:
- Call [Verification Token Interface] (Yggdrasil-Server Technical Specification #Verification Token), which contains the account's accessToken and clientToken.
- If the request is successful, the current credentials are valid and the process ends. Otherwise continue execution.
- Call [Refresh Interface] (Yggdrasil-Server Technical Specification #Refresh), which contains the account's accessToken and clientToken.
- If the request is successful, the account properties are updated with the information in the refresh response, and the process ends. Otherwise continue execution.
- The launcher asks the user to re-enter the password.
- Call the [login interface] (Yggdrasil-server technical specification#login), which contains the user's account and the password entered in the previous step.
- If
selectedProfile
is not empty in the login response, then:- If
selectedProfile
Theuuid
in is the same as the UUID of the account's corresponding role, then the user attributes are updated with the information in the login response. Process ends. - An exception is triggered (the role of the original account is no longer available).
- If
- Find the role from
availableProfiles
with the same UUID as the account's corresponding role. If not, an exception is triggered (the role of the original account is no longer available). - Call [Refresh Interface](Yggdrasil-Server Technical Specification#Refresh), where the token is the token returned by the login operation, and
selectedProfile
is the role found in the previous step. - The login is successful, and the account properties are updated with the information in the refresh response.
# Display of account information
When the launcher displays an account, in addition to the name of the role corresponding to the account, it should also display the authentication server to which the account belongs ([see above](#display of server name)), to prevent users from confusing roles with the same name on different authentication servers.
If the launcher wants to display the character skin, you can call [Query Character Attribute Interface](Yggdrasil-Server Technical Specification#Query Character Attribute) to get the character attribute, which contains the [character skin information](Yggdrasil-Server Technology Specification #Serialization of role information).
# start the game
The launcher needs to do the following before starting the game:
- (if needed) download authlib-injector
- [Confirm the validity of the certificate] (#Confirmation of the validity of the certificate)
- [Configure prefetch](#Configure prefetch)
- [Add startup parameters](#Add startup parameters)
Among them, steps 1, 2, and 3 can be executed in parallel to improve startup speed.
# Download authlib-injector
The launcher can come with authlib-injector.jar, or download one (and cache it) before launching the game. This project provides an API for downloading authlib-injector.
If your users are mainly in mainland China, we recommend that you download from [BMCLAPI mirror] (get-authlib-injector#bmclapi-mirror).
# configure prefetch
Before launching, the launcher needs to send a GET request to the API address to obtain API metadata. This metadata is passed into the game at startup so that the authlib-injector doesn't have to request the authentication server directly, which improves startup speed and prevents game startup crashes due to network failures.
# Add startup parameters
# Configure authlib-injector
The launcher needs to add the following JVM arguments (should be added before the main class arguments):
- javaagent parameters:
-javaagent:{path to authlib-injector.jar}={authentication server API address}
- Configure prefetch:
-Dauthlibinjector.yggdrasil.prefetched={Base64 encoded API metadata}
Take example.yggdrasil.yushi.moe as an example:
- authlib-injector.jar is located at
/home/user/.launcher/authlib-injector.jar
. - The API address of the authentication server is
https://example.yggdrasil.yushi.moe/
. - Send a GET request to
https://example.yggdrasil.yushi.moe/
to get the API metadata:Base64 encoding the above response, we get:{"skinDomains":["yushi.moe"],"signaturePublickey":... (omitted)
eyJza2luRG9tYWluc... (omitted)
- Therefore, the added JVM parameters are:
-javaagent:/home/user/.launcher/authlib-injector.jar=https://example.yggdrasil.yushi.moe/ -Dauthlibinjector.yggdrasil.prefetched=eyJza2luRG9tYWluc... (omitted)
# Replace parameter template
The game version JSON file (versions/<version>/<version>.json
) specifies the parameters used by the launcher to start the game, and some of the validation-related parameter templates should be replaced as follows:
parameter template | replace with |
---|---|
${auth_access_token} | account's accessToken |
${auth_session} | accessToken for the account |
${auth_player_name} | Name of the role |
${auth_uuid} | UUID of the role (unsigned) |
${user_type} | mojang |
${user_properties} | User's properties (in JSON format) (replace with {} if not supported by the launcher) |