Description
When using the Android client with a self-hosted NetBird server (embedded IdP, local email/password authentication with TOTP MFA), the PKCE login flow hangs indefinitely after successfully completing MFA verification. The
Windows client works correctly with the same server and account.
Steps to Reproduce
- Configure self-hosted NetBird with embedded IdP (combined server mode)
- Create a local
- Create a local user with email/password + TOTP MFA enabled
- On Android client, select "Email" login option
- Enter email and password → success
- Enter TOTP code → success
- App hangs at this point — never completes login
Expected Behavior
After MFA verification succeeds, the app should extract the authorization code from the redirect and exchange it for a token, completing the login.
Actual Behavior
The app's embedded WebView receives a 303 redirect to http://localhost:53000/?code=xxx&state=xxx from the /oauth2/approval endpoint, but fails to intercept this redirect. The WebView appears to get stuck attempting to
load the localhost URL instead of the app capturing the authorization code from the URL.
Server-Side Evidence
Traefik access logs show the complete successful flow:
Password login success (303)
POST /oauth2/auth/local/login?... 303
MFA TOTP success (303)
POST /oauth2/mfa/totp?... 303
Approval redirects to localhost:53000 (303, 140 bytes)
GET /oauth2/approval?... 303 140
*** No subsequent POST /oauth2/token request from Android ***
For comparison, Windows client successfully issues POST /oauth2/token immediately after the approval redirect and completes login.
Environment
- Server version: 0.72.2 (combined server mode, embedded IdP)
- Android client: latest from Play Store
- Auth method: Local email/password + TOTP MFA
- Login option selected: "Email" (PKCE flow)
Workaround
Using the "SSO" login option (which triggers Device Authorization Flow) works correctly on Android. The device flow does not depend on localhost redirect interception.
Notes
- The Android client calls
GetPKCEAuthorizationFlow via gRPC and uses redirect_uri=http://localhost:53000/ with an embedded WebView (not an external browser).
- The issue appears to be that
shouldOverrideUrlLoading or equivalent WebView URL interception is not capturing the http://localhost:53000/ redirect after the 303 from /oauth2/approval.
- Device Flow (
POST /oauth2/device/code → poll token endpoint) has been verified working on the same Android device with the same account
Description
When using the Android client with a self-hosted NetBird server (embedded IdP, local email/password authentication with TOTP MFA), the PKCE login flow hangs indefinitely after successfully completing MFA verification. The
Windows client works correctly with the same server and account.
Steps to Reproduce
Expected Behavior
After MFA verification succeeds, the app should extract the authorization code from the redirect and exchange it for a token, completing the login.
Actual Behavior
The app's embedded WebView receives a
303redirect tohttp://localhost:53000/?code=xxx&state=xxxfrom the/oauth2/approvalendpoint, but fails to intercept this redirect. The WebView appears to get stuck attempting toload the localhost URL instead of the app capturing the authorization code from the URL.
Server-Side Evidence
Traefik access logs show the complete successful flow:
Password login success (303)
POST /oauth2/auth/local/login?... 303
MFA TOTP success (303)
POST /oauth2/mfa/totp?... 303
Approval redirects to localhost:53000 (303, 140 bytes)
GET /oauth2/approval?... 303 140
*** No subsequent POST /oauth2/token request from Android ***
For comparison, Windows client successfully issues
POST /oauth2/tokenimmediately after the approval redirect and completes login.Environment
Workaround
Using the "SSO" login option (which triggers Device Authorization Flow) works correctly on Android. The device flow does not depend on localhost redirect interception.
Notes
GetPKCEAuthorizationFlowvia gRPC and usesredirect_uri=http://localhost:53000/with an embedded WebView (not an external browser).shouldOverrideUrlLoadingor equivalent WebView URL interception is not capturing thehttp://localhost:53000/redirect after the 303 from/oauth2/approval.POST /oauth2/device/code→ poll token endpoint) has been verified working on the same Android device with the same account