unmojang / drasl

Yggdrasil-compatible API server for Minecraft
GNU General Public License v3.0
69 stars 11 forks source link

Cannot get new accessToken for same clientToken #53

Closed Proxwian closed 1 month ago

Proxwian commented 3 months ago

How to reproduce:

  1. Login with url https://drasl.unmojang.org/authenticate with clientToken (for example, "client-test")
  2. Use accessToken and clientToken from step 1 to post to url https://drasl.unmojang.org/validate - it returns 204 (OK)
  3. Repeat step 1
  4. Try to repeat step 2
  5. Got 403 Error

For some reason, drasl required to invalidate last accessToken for the same clientToken before you can log again. It doesn't seem to be work as expected

Proxwian commented 3 months ago

For example, http://minecraft.ely.by/auth/authenticate and http://minecraft.ely.by/auth/validate allows you to authenticate multiple times without need to invalidate last accessToken for clientToken first

evan-goode commented 3 months ago

Hmm, that sounds like the intended behavior. Mojang's "Legacy Authentication" API isn't available any more to check what theirs did, and I don't see it explictly said in the wiki.vg docs that old accessTokens for a client are invalidated when a new one is issued. But I would argue that it is correct that only one accessToken should be valid at a time for a given clientToken.

If Ely.by doesn't do it that way, I suspect that's a bug or implementation quirk on their part. Looks like they don't even have any mechanism to invalidate tokens: https://github.com/elyby/accounts/blob/16877d502dfa2f23173517e4f6c607c943a1ff70/api/modules/authserver/models/InvalidateForm.php#L34, since they're using JWTs statelessly, as JWTs were intended. Drasl uses JWTs also but they're invalidated using a version number that's stored in the DB.

This behavior would be easy to change or place behind a configuration option, but do you have a real-world example of why this behavior would be wanted?

IkyMax commented 1 month ago

Hmm, that sounds like the intended behavior. Mojang's "Legacy Authentication" API isn't available any more to check what theirs did, and I don't see it explictly said in the wiki.vg docs that old accessTokens for a client are invalidated when a new one is issued. But I would argue that it is correct that only one accessToken should be valid at a time for a given clientToken.

If Ely.by doesn't do it that way, I suspect that's a bug or implementation quirk on their part. Looks like they don't even have any mechanism to invalidate tokens: https://github.com/elyby/accounts/blob/16877d502dfa2f23173517e4f6c607c943a1ff70/api/modules/authserver/models/InvalidateForm.php#L34, since they're using JWTs statelessly, as JWTs were intended. Drasl uses JWTs also but they're invalidated using a version number that's stored in the DB.

This behavior would be easy to change or place behind a configuration option, but do you have a real-world example of why this behavior would be wanted?

Hey! i have one! Helios launcher works in this way! That's why i can't have multiple accounts on the launcher, because it invalidates the previous account access token whenever a new account is added!

evan-goode commented 1 month ago

Hmm, that sounds like the intended behavior. Mojang's "Legacy Authentication" API isn't available any more to check what theirs did, and I don't see it explictly said in the wiki.vg docs that old accessTokens for a client are invalidated when a new one is issued. But I would argue that it is correct that only one accessToken should be valid at a time for a given clientToken. If Ely.by doesn't do it that way, I suspect that's a bug or implementation quirk on their part. Looks like they don't even have any mechanism to invalidate tokens: https://github.com/elyby/accounts/blob/16877d502dfa2f23173517e4f6c607c943a1ff70/api/modules/authserver/models/InvalidateForm.php#L34, since they're using JWTs statelessly, as JWTs were intended. Drasl uses JWTs also but they're invalidated using a version number that's stored in the DB. This behavior would be easy to change or place behind a configuration option, but do you have a real-world example of why this behavior would be wanted?

Hey! i have one! Helios launcher works in this way! That's why i can't have multiple accounts on the launcher, because it invalidates the previous account access token whenever a new account is added!

I think I understand now. The real issue IMO is that multiple users might use the same client token, but we assume client tokens are unique to each user. I opened https://github.com/unmojang/drasl/pull/72, which should fix it. #72 will not, however, allow the same user to have multiple accessTokens under the same user/clientToken combination.

I tried to check whether my PR would fix your issue with Helios Launcher, but I couldn't figure out how to log in to a third-party account. Are you perhaps using a fork of Helios that adds authlib-injector support?

IkyMax commented 1 month ago

I tried to check whether my PR would fix your issue with Helios Launcher, but I couldn't figure out how to log in to a third-party account. Are you perhaps using a fork of Helios that adds authlib-injector support?

Actually im using the Mojang login what is embedded inside Helios launcher, in order to use it correctly i'm using a custom Helios-core npm module, this is the file what used the old mojang auth endopint, and this is the one i'm using in my launcher with a Blessing skins + Yggdrasil plugin instance

IkyMax commented 1 month ago

Actually im using the Mojang login what is embedded inside Helios launcher, in order to use it correctly i'm using a custom Helios-core npm module, this is the file what used the old mojang auth endopint, and this is the one i'm using in my launcher with a Blessing skins + Yggdrasil plugin instance

Helios is capable of use the Mojang API of Drasl or use the Authlib Injector endpoints in Drasl, i just need to add the /authserver behind every endpoint (i.e. /validate = /authserver/validate)

evan-goode commented 1 month ago

I see, would you mind testing https://github.com/unmojang/drasl/pull/72 then? I would back up your Drasl database first if you do.

IkyMax commented 1 month ago

I see, would you mind testing https://github.com/unmojang/drasl/pull/72 then? I would back up your Drasl database first if you do.

Sure! It's the Docker image up or i should use the manual installation?

evan-goode commented 1 month ago

It's only on a branch on my fork at the moment, so you would need to:

  1. Clone the repo (if you haven't done so already)
git clone https://github.com/unmojang/drasl.git
cd drasl
  1. Add and fetch my remote
git remote add evan-goode https://github.com/evan-goode/drasl.git
git fetch evan-goode
  1. Check out the branch
git checkout evan-goode/allow-duplicate-client-tokens

From there I think you can proceed with the manual installation steps.

IkyMax commented 1 month ago

I tried to set up drasl on default config and it just throws with status

× drasl.service - Drasl
     Loaded: loaded (/etc/systemd/system/drasl.service; enabled; preset: enabled)
     Active: failed (Result: exit-code) since Tue 2024-05-14 02:49:51 UTC; 3s ago
   Duration: 51ms
    Process: 80097 ExecStart=/usr/local/bin/drasl (code=exited, status=1/FAILURE)
   Main PID: 80097 (code=exited, status=1/FAILURE)
        CPU: 51ms

May 14 02:49:51 authtest.us-central1-a.c.true-truck-385617.internal systemd[1]: drasl.service: Scheduled restart job, restart counter is at 5.
May 14 02:49:51 authtest.us-central1-a.c.true-truck-385617.internal systemd[1]: Stopped drasl.service - Drasl.
May 14 02:49:51 authtest.us-central1-a.c.true-truck-385617.internal systemd[1]: drasl.service: Start request repeated too quickly.
May 14 02:49:51 authtest.us-central1-a.c.true-truck-385617.internal systemd[1]: drasl.service: Failed with result 'exit-code'.
May 14 02:49:51 authtest.us-central1-a.c.true-truck-385617.internal systemd[1]: Failed to start drasl.service - Drasl.
evan-goode commented 1 month ago

I just realized the manual install steps will have Drasl looking in the wrong DataDirectory. I pushed a commit to fix that.

Try doing a git pull in the repo, then run sudo make install again and this time run it without systemd, just run drasl.

IkyMax commented 1 month ago

Hey! srry, i responded in the pr instead of this issue

evan-goode commented 1 month ago

Should be fixed in https://github.com/unmojang/drasl/pull/72