Fix a crash when initialising StreamVideoClient with a UserType.Guest#1637
Fix a crash when initialising StreamVideoClient with a UserType.Guest#1637aleksandar-apostolov merged 6 commits intodevelopfrom
StreamVideoClient with a UserType.Guest#1637Conversation
PR checklist ✅All required conditions are satisfied:
🎉 Great job! This PR is ready for review. |
WalkthroughThis PR introduces guest sign-in support to the Stream Video Android SDK. Changes span the demo app's login UI, SDK initialization helpers, token validation logic, and network authentication handling. Key additions include new guest/anonymous initialization methods, adjusted WebSocket connection behavior for different user types, and updated tests validating guest user flows. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant LoginScreen
participant LoginViewModel
participant DataStore
participant StreamVideoInitHelper
participant StreamVideoBuilder
participant StreamVideo as StreamVideo SDK
User->>LoginScreen: Tap "Sign in as Guest"
LoginScreen->>LoginViewModel: emit SignInAsGuest event
LoginViewModel->>LoginViewModel: signInAsGuest() flow triggered
LoginViewModel->>LoginViewModel: Generate random guest ID
LoginViewModel->>DataStore: updateUser(guestUser with UserType.Guest)
DataStore-->>LoginViewModel: User persisted
LoginViewModel->>StreamVideoInitHelper: loadSdkForGuest(dataStore, guestUser)
StreamVideoInitHelper->>StreamVideoBuilder: Initialize SDK with blank token
StreamVideoBuilder->>StreamVideoBuilder: Skip token validation for Guest type
StreamVideoBuilder->>StreamVideo: initializeStreamVideo(token="", user=guestUser)
StreamVideo-->>StreamVideoBuilder: SDK initialized
StreamVideoInitHelper->>StreamVideo: connect() via instanceOrNull()
StreamVideo-->>StreamVideoInitHelper: WebSocket connected
StreamVideoInitHelper->>LoginViewModel: emit GuestSignInComplete
LoginViewModel->>LoginScreen: Update UI state
LoginScreen->>User: Navigate to call join screen
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related issues
Poem
🚥 Pre-merge checks | ✅ 1 | ❌ 2❌ Failed checks (2 warnings)
✅ Passed checks (1 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 4
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
demo-app/src/main/kotlin/io/getstream/video/android/ui/login/LoginViewModel.kt (1)
178-198:⚠️ Potential issue | 🟠 MajorGuest users fail to re-login on app restart.
signInIfValidUserExist()always emitsLoginEvent.SignInSuccessfor any stored user, which routes tosignInSuccess()and fetches a server-side token viaStreamService.instance.getAuthData(). For guest users (stored withtype = UserType.Guest), this is incorrect—they should go throughsignInAsGuest()instead, which usesStreamVideoInitHelper.loadSdkForGuest()with an empty token.This breaks the re-login flow: if a guest signs in, kills the app, and restarts, the app will attempt to fetch a server token for the guest user, causing sign-in to fail.
Proposed fix
fun signInIfValidUserExist() { viewModelScope.launch { val user = dataStore.user.firstOrNull() if (user != null) { handleUiEvent(LoginEvent.Loading) if (BuildConfig.BUILD_TYPE != "benchmark") { delay(10) - handleUiEvent(LoginEvent.SignInSuccess(userId = user.id)) + if (user.type == UserType.Guest) { + handleUiEvent(LoginEvent.SignInAsGuest) + } else { + handleUiEvent(LoginEvent.SignInSuccess(userId = user.id)) + } } } else { if (autoLogIn) { handleUiEvent(LoginEvent.Loading) handleUiEvent( LoginEvent.SignInSuccess( UserHelper.generateRandomString(upperCaseOnly = true), ), ) } } } }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@demo-app/src/main/kotlin/io/getstream/video/android/ui/login/LoginViewModel.kt` around lines 178 - 198, signInIfValidUserExist incorrectly treats stored guest users as normal users; update LoginViewModel.signInIfValidUserExist so that after retrieving user = dataStore.user.firstOrNull() it checks if user.type == UserType.Guest and, if so, emits the guest path (e.g. handleUiEvent(LoginEvent.SignInAsGuest(userId = user.id)) or otherwise trigger the signInAsGuest flow) instead of LoginEvent.SignInSuccess; keep the existing BUILD_TYPE benchmark delay and current non-guest behavior unchanged for non-guest users.
🧹 Nitpick comments (1)
demo-app/src/main/kotlin/io/getstream/video/android/util/StreamVideoInitHelper.kt (1)
360-360: HardcodedHttpLoggingLevel.BODYmay expose sensitive data.Forcing
HttpLoggingLevel.BODYoverrides the caller'sloggingLeveland logs full HTTP request/response bodies. This could expose JWTs and other sensitive tokens in logs, which conflicts with the coding guideline to "Sanitize logs to avoid dumping JWTs, ICE tokens, or call IDs in verbose logs."Consider making this conditional on debug builds or removing the override to respect the caller's logging preferences.
♻️ Suggested fix for debug-only body logging
- loggingLevel = loggingLevel.copy(httpLoggingLevel = HttpLoggingLevel.BODY), + loggingLevel = if (BuildConfig.DEBUG) { + loggingLevel.copy(httpLoggingLevel = HttpLoggingLevel.BODY) + } else { + loggingLevel + },As per coding guidelines: "Sanitize logs to avoid dumping JWTs, ICE tokens, or call IDs in verbose logs."
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@demo-app/src/main/kotlin/io/getstream/video/android/util/StreamVideoInitHelper.kt` at line 360, The code currently forces loggingLevel = loggingLevel.copy(httpLoggingLevel = HttpLoggingLevel.BODY), which can leak sensitive data; change this to respect the caller or enable BODY only for debug builds (e.g. use BuildConfig.DEBUG or a passed-in debug flag) — update the assignment in StreamVideoInitHelper (the loggingLevel variable) so that HttpLoggingLevel.BODY is applied only when in debug mode, otherwise leave loggingLevel.httpLoggingLevel unchanged or set a safer default (e.g. HEADERS or NONE).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In
`@demo-app/src/main/kotlin/io/getstream/video/android/util/StreamVideoInitHelper.kt`:
- Around line 185-230: The isInitialising flag in loadSdkForGuest is not reset
when an exception is thrown because isInitialising = false is after the thrown
exception; wrap the init logic in a try { ... } finally { isInitialising = false
} (or move the flag reset into a finally block) so isInitialising is always set
to false regardless of success or failure; update loadSdkForGuest to set
isInitialising = true before the try and reset it in finally, keeping the
existing catch behavior for setting _initState and rethrowing the exception.
- Around line 232-275: loadSdkForAnonymous has the same missing start guard and
non-guaranteed reset of isInitialising as loadSdkForGuest; add a guard at the
top of loadSdkForAnonymous that returns early if isInitialising is true (same
behavior as loadSdkForGuest), and move the isInitialising = false assignment
into a finally block so it always executes after the try/catch around
initializeStreamVideo / dataStore.updateUser; ensure _initState updates remain
in the try/catch as they are and reference the existing symbols
loadSdkForAnonymous, isInitialising, _initState, initializeStreamVideo, and
dataStore.updateUser when making the change.
- Around line 194-200: Add the same isInitialising guard used in loadSdk to
loadSdkForGuest to prevent concurrent inits: check isInitialising at the start
of loadSdkForGuest (alongside the existing StreamVideo.isInstalled check) and
return early if true, so you only set isInitialising = true and _initState.value
= InitializedState.RUNNING when no initialization is already in progress;
reference the loadSdk method's guard pattern and the symbols isInitialising,
loadSdkForGuest, StreamVideo.isInstalled, and _initState/InitializedState.
In
`@stream-video-android-ui-core/src/main/kotlin/io/getstream/video/android/ui/common/StreamCallActivity.kt`:
- Line 889: Remove the debug/placeholder inline comments "// noob" left next to
the EXTRA_JOIN_AND_RING usage; specifically edit the code that reads val
joinAndRing = intent.getBooleanExtra(EXTRA_JOIN_AND_RING, false) (and the other
occurrence near the second EXTRA_JOIN_AND_RING usage) and delete the trailing
comment so only the declaration remains, keeping behavior unchanged.
---
Outside diff comments:
In
`@demo-app/src/main/kotlin/io/getstream/video/android/ui/login/LoginViewModel.kt`:
- Around line 178-198: signInIfValidUserExist incorrectly treats stored guest
users as normal users; update LoginViewModel.signInIfValidUserExist so that
after retrieving user = dataStore.user.firstOrNull() it checks if user.type ==
UserType.Guest and, if so, emits the guest path (e.g.
handleUiEvent(LoginEvent.SignInAsGuest(userId = user.id)) or otherwise trigger
the signInAsGuest flow) instead of LoginEvent.SignInSuccess; keep the existing
BUILD_TYPE benchmark delay and current non-guest behavior unchanged for
non-guest users.
---
Nitpick comments:
In
`@demo-app/src/main/kotlin/io/getstream/video/android/util/StreamVideoInitHelper.kt`:
- Line 360: The code currently forces loggingLevel =
loggingLevel.copy(httpLoggingLevel = HttpLoggingLevel.BODY), which can leak
sensitive data; change this to respect the caller or enable BODY only for debug
builds (e.g. use BuildConfig.DEBUG or a passed-in debug flag) — update the
assignment in StreamVideoInitHelper (the loggingLevel variable) so that
HttpLoggingLevel.BODY is applied only when in debug mode, otherwise leave
loggingLevel.httpLoggingLevel unchanged or set a safer default (e.g. HEADERS or
NONE).
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: dd4b3f1d-ac7c-40af-8a25-e21900441e27
📒 Files selected for processing (10)
build.gradle.ktsdemo-app/src/main/kotlin/io/getstream/video/android/ui/login/LoginScreen.ktdemo-app/src/main/kotlin/io/getstream/video/android/ui/login/LoginViewModel.ktdemo-app/src/main/kotlin/io/getstream/video/android/util/StreamVideoInitHelper.ktdemo-app/src/main/res/values/strings.xmlstream-video-android-core/src/main/kotlin/io/getstream/video/android/core/StreamVideoBuilder.ktstream-video-android-core/src/main/kotlin/io/getstream/video/android/core/StreamVideoClient.ktstream-video-android-core/src/main/kotlin/io/getstream/video/android/core/internal/module/CoordinatorAuthInterceptor.ktstream-video-android-core/src/test/kotlin/io/getstream/video/android/core/ClientAndAuthTest.ktstream-video-android-ui-core/src/main/kotlin/io/getstream/video/android/ui/common/StreamCallActivity.kt
demo-app/src/main/kotlin/io/getstream/video/android/util/StreamVideoInitHelper.kt
Show resolved
Hide resolved
demo-app/src/main/kotlin/io/getstream/video/android/util/StreamVideoInitHelper.kt
Show resolved
Hide resolved
demo-app/src/main/kotlin/io/getstream/video/android/util/StreamVideoInitHelper.kt
Outdated
Show resolved
Hide resolved
...o-android-ui-core/src/main/kotlin/io/getstream/video/android/ui/common/StreamCallActivity.kt
Outdated
Show resolved
Hide resolved
SDK Size Comparison 📏
|
demo-app/src/main/kotlin/io/getstream/video/android/util/StreamVideoInitHelper.kt
Outdated
Show resolved
Hide resolved
demo-app/src/main/kotlin/io/getstream/video/android/util/StreamVideoInitHelper.kt
Outdated
Show resolved
Hide resolved
aleksandar-apostolov
left a comment
There was a problem hiding this comment.
SDK fixes look good. LGTM.
|
StreamVideoClient with a UserType.Guest
|
🚀 Available in v1.21.0 |



Goal
Fix a crash in the Android SDK when initialising
StreamVideoClientwith aUserType.Guestuser and no token. On iOS and React, the SDK silently calls /video/guest to obtain a JWT automatically — Android should behave the same way.Additionally, the demo app incorrectly treated Guest and Anonymous as the same login path. This PR separates the two user types with correct labels and distinct entry points in the login UI.
Implementation
SDK — two bug fixes:
StreamVideoBuilder — token blank validation was applied unconditionally to all user types. Scoped the check to UserType.Authenticated only. Guest users pass no token; the SDK internally calls POST /video/guest to fetch a JWT via guestUserJob.
CoordinatorAuthInterceptor — when token was blank (guest/anonymous), the interceptor still appended an Authorization: header with an empty string, causing the server to return HTTP 403. Added a guard so the Authorization header is only added when the token is non-blank.
🎨 UI Changes
Testing
Summary by CodeRabbit