Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

"Refresh Token Not Found" = automatic logout after 2-3 days after login #486

Open
2 tasks done
EduardMe opened this issue Aug 1, 2024 · 29 comments
Open
2 tasks done
Labels
bug Something isn't working

Comments

@EduardMe
Copy link

EduardMe commented Aug 1, 2024

Bug report

  • I confirm this is a bug with Supabase, not with my own application.
  • I confirm I have searched the Docs, GitHub Discussions, and Discord.

Describe the bug

About 2-3 days after logging in, the user gets automatically logged out (we are using the OTP login and use the API on iOS and macOS). Checking the error messages, we see:

api(Auth.AuthError.APIError(msg: nil, code: nil, error: Optional("invalid_grant"), errorDescription: Optional("Invalid Refresh Token: Refresh Token Not Found"), weakPassword: nil))

To Reproduce

Using the Swift API of Supabase, login, use the app for 2-3 days and you will get logged out.

Expected behavior

User should stay logged in indefinitely or as per the settings (see additional information).

System information

  • OS: macOS, iOS
  • Version of supabase-swift: 2.15.2

Additional context

We have tried to increase the rate limits:
Token Refreshes = 184
Token Verifications = 100
Sign ups and sign ins = 50
Time-box user sessions = 0
Inactivity timeout = 0
Access Tokens expiry time = 10800 (3 hours)
Refresh token reuse interval = 30

Let me know if the settings can cause this.

@EduardMe EduardMe added the bug Something isn't working label Aug 1, 2024
@hf
Copy link

hf commented Aug 2, 2024

This is likely due to a bug in your application that refreshes the token in parallel. Please see this doc for more information about such issues: https://supabase.com/docs/guides/auth/sessions#what-is-refresh-token-reuse-detection-and-what-does-it-protect-from

@hf
Copy link

hf commented Aug 2, 2024

Also be aware that if the user signed out from another device or platform (web) they are signed out from everywhere. You can control this with a parameter.

@EduardMe
Copy link
Author

EduardMe commented Aug 2, 2024

Thanks for the quick reply. We have called refreshSession when an invalid_grant error was received. Can this cause the problem? I have removed that and also set the scope of signOut to global. Though I don't think this was the issue, but could have added some confusion. Will monitor this the next few days.

@EduardMe
Copy link
Author

EduardMe commented Aug 5, 2024

Ok, after about 2-3 days of testing with the changes, I'm still getting logged out automatically on macOS (2x in the last 2-3 days) with the error message:

api(Auth.AuthError.APIError(msg: nil, code: nil, error: Optional("invalid_grant"), errorDescription: Optional("Invalid Refresh Token: Already Used"), weakPassword: nil))

I haven't hit the logout button anywhere during testing.

Any ideas how to fix it or if it's a bug in the library?

@grdsdev
Copy link
Collaborator

grdsdev commented Aug 5, 2024

Hi @EduardMe

do you have any extension also using Supabase? Widgets...

@EduardMe
Copy link
Author

EduardMe commented Aug 6, 2024

Just checked, we have a Widget, but it accesses only some userDefaults.

We have shortcuts that call the CloudKit sync, possibly Supabase, however, I'm not using them.

Today I got logged out again on macOS. I use it less on iOS, but there I didn't get logged out since testing. So it's just on macOS since the last 3 days.

On macOS I often run into some internet connection issues. It gets disconnected for a second. Might this influence it?

@grdsdev
Copy link
Collaborator

grdsdev commented Aug 7, 2024

Thanks @EduardMe

I'm investigating it, and will post any updates I find on this issue.

@LucasAbijmil
Copy link
Contributor

I'm having the same issue since I updated my version of Supabase in my Xcode project. I don't do anything sophisticated in my app and the token settings are the default

@grdsdev
Copy link
Collaborator

grdsdev commented Aug 7, 2024

@LucasAbijmil which version were you using before, which you wasn't having this issue?

@LucasAbijmil
Copy link
Contributor

@grdsdev Previously I was in 2.5.1, then it was when I switched to 2.13.3 that the bug seems to have been introduced

@EduardMe
Copy link
Author

EduardMe commented Aug 9, 2024

@grdsdev I have some idea, but I'm not quite sure. Is it possible that if this gets called in parallel or when the Supabase library refreshes the session in the background and we call it at the same time it creates an issue?

We are using this func in Swift to check if the user is logged in:

func session(completion: @escaping (Result<Session, Error>) -> Void) {
    Task {
	    do {
		    if let currentSession = supabase.auth.currentSession, !currentSession.isExpired {
			    completion(.success(currentSession))
			    return
		    }
		    
		    let session = try await supabase.auth.session
		    completion(.success(session))
	    } catch {
		    completion(.failure(error))
	    }
    }
}

@grdsdev
Copy link
Collaborator

grdsdev commented Aug 9, 2024

@EduardMe I don't think that is causing the issue, but your check is redundant, when you call the try await supabase.auth.session it already validates if session is expired, if it isn't, it returns it without refreshing, just like your first if.

Still looking at this issue...

@dpelletier2017
Copy link

dpelletier2017 commented Aug 19, 2024

This might be the bug I'm experiencing since December, the day I implemented Sign In With Apple in my SwiftUI App.
It seems to happen randomly. When I develop the app, it can happen 3-4 times in an afternoon because I launch my app often, but other than that yes it seems to be happening every 2-3 days. It basically logs my users out from time to time.

Ideally, I'd like the user to just login the first time and then never again unless he stops using the app for a prolonged period, or he deletes the app and reinstalls it or upgrades to a new phone.

api(Auth.AuthError.APIError(msg: nil, code: nil, error: Optional("invalid_grant"), errorDescription: Optional("Invalid Refresh Token: Refresh Token Not Found"), weakPassword: nil))

I've indeed seen that happen quite a lot of times. That along with "Bad ID token". I can't put my finger on it, but there's something not working well with Supabase Auth in Swift.

FYI I never call the refreshSession() function, because the Docs says :
try await supabase.auth.session // Returns the session, refreshing it if necessary
I tried using the refreshSession() function and the bug was still there, so I removed it in my production code.

@EduardMe
Copy link
Author

EduardMe commented Aug 22, 2024

For us the error is usually Invalid Refresh Token: Already Used. That's the only bigger roadblock for us right now. The rest works great. We haven't use the API for that long, so I haven't seen a version where it worked for more than 2-3 days.

@EduardMe
Copy link
Author

@grdsdev Could you find anything? We are a bit struggling with this, or is there anything we can do temporarily to reduce the logouts?

@iBenjamin
Copy link

2024-09-10T17:37:30+0800 supabase: Response: Status code: 400 Content-Length: 83 Body: { "error" : "invalid_grant", "error_description" : "Invalid Refresh Token: Already Used" }
same here

@pedrommcarrasco
Copy link

Hey 👋
Could we please bring more attention to this issue? It’s a crucial part of the core workflow for many apps, and addressing it promptly would be greatly appreciated.

@rebryk
Copy link

rebryk commented Sep 13, 2024

I receive an error with 2.14.0. Sometimes the app works less than a day.
2024-09-12T19:14:44-0700 error BroadcastReducer : [n/a] Failed to create realtime channel: api(Auth.AuthError.APIError(msg: nil, code: nil, error: Optional("invalid_grant"), errorDescription: Optional("Invalid Refresh Token: Already Used"), weakPassword: nil))

I have my actor that updates the current session that might be accessed from different places:

  func session(from: URL? = nil) async throws -> Session {
    if let task {
      return try await task.value
    }

    task = Task {
      defer { self.task = nil }

      if let from {
        return try await supabase.auth.session(from: from)
      } else {
        return try await supabase.auth.session
      }
    }

    return try await task!.value
  }

@rebryk
Copy link

rebryk commented Sep 13, 2024

@EduardMe Have you managed to codesign the app with SDK 2.14+? Have you granted Keychain Sharing capabilities to the app?

@rebryk
Copy link

rebryk commented Sep 14, 2024

SDK v2.8.0 has same the problem

2024-09-13T17:49:05-0700 debug BroadcastReducer : [n/a] Channel status changed: unsubscribing
2024-09-13T18:07:28-0700 warning BackendService : [n/a] Attempt 1 failed: api(Auth.AuthError.APIError(msg: nil, code: nil, error: Optional("invalid_grant"), errorDescription: Optional("Invalid Refresh Token: Refresh Token Not Found"), weakPassword: nil))

@grdsdev i used v2.0 before, if i am not mistaken, and it was fine. however, not sure that it has realtime. i need realtime that is why i decided to upgrade at all

@dpelletier2017
Copy link

AFAIK the bug's been there since at least December 2023 because this is when I started designing my app and it's been a day 1 bug for me.

Yes, this requires more attention, it is currently my only bug with Supabase, but it's a big one. It's really annoying my users.

I only implemented Sign In With Apple FYI, in Swift/SwiftUI.

Also, logging in with a device seems to log out other devices. I always have to login between the Simulator and my real iPhone.

@dshukertjr
Copy link
Member

These types of errors are hard to track down the cause. If anyone is able to reliably reproduce the issue, sharing the steps would greatly help us track down what might be the cause.

@EduardMe
Copy link
Author

@EduardMe Have you managed to codesign the app with SDK 2.14+? Have you granted Keychain Sharing capabilities to the app?

@rebryk Yes, I have granted Keychain Sharing, but I did this long before, didn't even know I needed to do this. Haven't done anything else to set things up. Just had to bump up the minimum version for macOS and iOS builds.

@rebryk
Copy link

rebryk commented Sep 15, 2024

@dshukertjr i can add supabase logger and wait for a few hours when it actually will happen. will it help you?

@dshukertjr
Copy link
Member

@rebryk That might help us out 👍

@rebryk
Copy link

rebryk commented Sep 21, 2024

@dshukertjr @grdsdev I have logs. What email should I use to send them?

@dshukertjr
Copy link
Member

@rebryk Can you just hide what you need to hide and paste it here?

@rebryk
Copy link

rebryk commented Sep 24, 2024

@dshukertjr i don't know how to do that with .pulse log

@rebryk
Copy link

rebryk commented Sep 24, 2024

@dshukertjr in my case it happens with realtime.

2024-09-16T04:51:13Z [verbose] [Realtime] [Realtime/WebSocketClient.send(_:):111] Sending message: {"event":"heartbeat","payload":{},"topic":"phoenix","ref":"233"}

2024-09-16T04:51:13Z [verbose] [Realtime] [Realtime/WebSocketClient.receive():88] Received message: {"ref":"233","event":"phx_reply","payload":{"status":"ok","response":{}},"topic":"phoenix"}

2024-09-16T04:51:13Z [debug] [Realtime] [Realtime/RealtimeClientV2.onMessage(_:):328] heartbeat received

2024-09-16T04:51:16Z [verbose] [Realtime] [Realtime/WebSocketClient.receive():88] Received message: {"ref":null,"event":"system","payload":{"message":"Access token has expired: [message: \"Invalid token\", claim: \"exp\", claim_val: 1726462276]","status":"error","extension":"system","channel":"b0412dd4-fffc-4058-ab0d-2531f88fd6d9"},"topic":"realtime:b0412dd4-fffc-4058-ab0d-2531f88fd6d9"}

2024-09-16T04:51:16Z [debug] [Realtime] [Realtime/RealtimeClientV2.onMessage(_:):331] Received event system for channel realtime:b0412dd4-fffc-4058-ab0d-2531f88fd6d9

2024-09-16T04:51:16Z [debug] [Realtime] [Realtime/RealtimeChannelV2.onMessage(_:):210] Received message without event type: RealtimeMessageV2(joinRef: nil, ref: nil, topic: "realtime:b0412dd4-fffc-4058-ab0d-2531f88fd6d9", event: "system", payload: ["channel": b0412dd4-fffc-4058-ab0d-2531f88fd6d9, "message": Access token has expired: [message: "Invalid token", claim: "exp", claim_val: 1726462276], "status": error, "extension": system])

2024-09-16T04:51:16Z [verbose] [Realtime] [Realtime/WebSocketClient.receive():88] Received message: {"ref":"1","event":"phx_close","payload":{},"topic":"realtime:b0412dd4-fffc-4058-ab0d-2531f88fd6d9"}

2024-09-16T04:51:16Z [debug] [Realtime] [Realtime/RealtimeClientV2.onMessage(_:):331] Received event phx_close for channel realtime:b0412dd4-fffc-4058-ab0d-2531f88fd6d9

2024-09-16T04:51:16Z [debug] [Realtime] [Realtime/RealtimeChannelV2.unsubscribe():116] unsubscribing from channel realtime:b0412dd4-fffc-4058-ab0d-2531f88fd6d9

2024-09-16T04:51:16Z [debug] [Realtime] [Realtime/RealtimeChannelV2.onPresenceChange(_:):350] Removing presence callback with id: 1

2024-09-16T04:51:16Z [verbose] [Realtime] [Realtime/WebSocketClient.send(_:):111] Sending message: {"join_ref":"1","topic":"realtime:b0412dd4-fffc-4058-ab0d-2531f88fd6d9","ref":"234","payload":{},"event":"phx_leave"}

2024-09-16T04:51:16Z [debug] [Realtime] [Realtime/RealtimeChannelV2.onBroadcast(event:callback:):447] Removing broadcast callback with id: 2

2024-09-16T04:51:16Z [debug] [Realtime] [Realtime/RealtimeClientV2.removeChannel(_:):229] No more subscribed channel in socket

2024-09-16T04:51:16Z [debug] [Realtime] [Realtime/RealtimeClientV2.disconnect():302] Closing WebSocket connection

2024-09-16T04:51:16Z [debug] [Realtime] [Realtime/RealtimeChannelV2.onBroadcast(event:callback:):447] Removing broadcast callback with id: 3

2024-09-16T04:51:16Z [debug] [Realtime] [Realtime/RealtimeChannelV2.onMessage(_:):322] Unsubscribed from channel realtime:b0412dd4-fffc-4058-ab0d-2531f88fd6d9

2024-09-16T04:51:16Z [debug] [Realtime] [Realtime/RealtimeClientV2.removeChannel(_:):229] No more subscribed channel in socket

2024-09-16T04:51:16Z [debug] [Realtime] [Realtime/RealtimeClientV2.disconnect():302] Closing WebSocket connection

2024-09-16T04:51:16Z [verbose] [_Helpers] [_Helpers/Request.rawFetch(_:):25] Request [2773CEC7-44CE-47DB-ADC8-B71579E7660C]: POST https://<PROJECT_ID>.supabase.co/auth/v1/token?grant_type=refresh_token
Body: {
  "refresh_token" : "Cl9XpqzeHzUxSuee1Bbzdg"
}

2024-09-16T04:51:16Z [verbose] [_Helpers] [_Helpers/Request.rawFetch(_:):45] Response [2773CEC7-44CE-47DB-ADC8-B71579E7660C]: Status code: 400 Content-Length: 94
Body: {
  "error" : "invalid_grant",
  "error_description" : "Invalid Refresh Token: Refresh Token Not Found"
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

9 participants