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

[Bug]: Apple Auth is broken #447

Open
jan-tennert opened this issue Jan 30, 2024 · 8 comments
Open

[Bug]: Apple Auth is broken #447

jan-tennert opened this issue Jan 30, 2024 · 8 comments
Assignees
Labels
bug Something isn't working help wanted Extra attention is needed

Comments

@jan-tennert
Copy link
Collaborator

jan-tennert commented Jan 30, 2024

thanks @jan-tennert , I was able to run it locally and have found out where the issue is happening, still not sure if it is something on my end but here is what I found

and Should I create a new issue with these details?

I have added the code and the logs output below

I put some logs in the method "rememberSignInWithApple" and here are my obervations

1.The method runs as soon as the app opens, without user doing anything, although the code inside launched effect doesnt runs and directly the last log is printed

  1. Then when I click on the sign in button all the statments that are marked "executed" run in an instant without me doing anything

3.Nothing is executed after I click on "signIn"(after putting password in the box) in the apple native signin ui

4."nonce" and the "user" properties are showing null

5.All properties inside the config.loginConfig["apple"] object are null, even though object is not null

6.IMPORTANT -looks like authorizationController() method is never executed, I had put some logs in that method too but nothing was printed and also the print statement "I am here 10" was not printed

@Composable
actual fun ComposeAuth.rememberSignInWithApple(
    onResult: (NativeSignInResult) -> Unit,
    fallback: suspend () -> Unit
): NativeSignInState {

    val state = remember { NativeSignInState() }
    val scope = rememberCoroutineScope()

    LaunchedEffect(key1 = state.started) {
        println("I am inside launched effect")//executed
        if (state.started) {
            println("I am inside first if block , which means state is set to started")//executed

            println("${config.loginConfig["apple"]}")
            if (config.loginConfig["apple"] == null) {
                println("I am inside 2nd if block , which shouldn't happen")// NOT EXECUTED
                fallback.invoke()
                state.reset()
                return@LaunchedEffect
            }

            val appleIDProvider = ASAuthorizationAppleIDProvider()
            val request = appleIDProvider.createRequest().apply {
                requestedScopes = listOf(ASAuthorizationScopeFullName, ASAuthorizationScopeEmail)
                nonce = (config.loginConfig["apple"] as? AppleLoginConfig)?.nonce
                println("loginConfig - ${config.loginConfig["apple"]}  server client id - ${config.loginConfig["apple"]?.serverClientId}")//executed
                println("requested scopes - $requestedScopes , nounce - $nonce  ")//executed
            }
            println("request - $request - user - ${request.user}")//executed


            val controller = ASAuthorizationController(listOf(request)).apply {
                println("i m inside controller ${this.delegate}")//executed
                delegate = authorizationController(scope) {
                    println(" I m here 10")// **** NOT EXECUTED ****
                    onResult.invoke(it)
                    state.reset()
                }

                println("I am here in the controller") // EXECUTED

                presentationContextProvider = presentationAnchor()


            }
            println("controller - $controller - delegate ${controller.delegate}") // EXECUTED
            println(" i am on my way further 3") // EXECUTED
            controller.performRequests()

            println("I am after the perfrom Reuest function")

        }
    }
    println("I am outside launched effect and state is $state.") //Executed first

    return state
}

##output

I am outside launched effect and state is io.github.jan.supabase.compose.auth.composable.NativeSignInState@8a32be0. I am inside launched effect starting apple auth I am outside launched effect and state is io.github.jan.supabase.compose.auth.composable.NativeSignInState@8a32be0. I am inside launched effect I am inside first if block , which means state is set to started AppleLoginConfig(serverClientId=, nonce=null, extraData=null) loginConfig - AppleLoginConfig(serverClientId=, nonce=null, extraData=null) server client id - requested scopes - [full_name, email] , nounce - null request - <ASAuthorizationAppleIDRequest: 0x60000213c820> - user - null i m inside controller null I am here in the controller controller - <ASAuthorizationController: 0x60000390a2f0> - delegate <ComposeApp_kobjc5: 0x600000260740> i am on my way further 3 I am after the perfrom Reuest function

Originally posted by @Vaibhav-214 in #446 (comment)

@jan-tennert jan-tennert self-assigned this Jan 30, 2024
@jan-tennert jan-tennert added the bug Something isn't working label Jan 30, 2024
@jan-tennert jan-tennert changed the title Apple Auth is broken Bug: Apple Auth is broken Jan 30, 2024
@jan-tennert jan-tennert changed the title Bug: Apple Auth is broken [Bug]: Apple Auth is broken Jan 30, 2024
@jan-tennert
Copy link
Collaborator Author

Okay so points 1, 2, 4, 5 are normal. I'm not sure why the server client id property even exists as it's not used anyway, but I think its not needed. For point 6 I'm not sure, @temk0 implemented this, so maybe he can help with this. The authorization controller method is a little bit below the composable, are any of those functions implemented called at all? In any case, I'm gonna mark as help needed, as I can't test it myself.

@jan-tennert jan-tennert added the help wanted Extra attention is needed label Jan 30, 2024
@Vaibhav-214
Copy link

Vaibhav-214 commented Jan 30, 2024

I had put some print statements in both the authorization controller methods (different parameters) but they never got executed.

Also I think code never reached to a point where it would execute this signInWithApple() method as it is called inside authorization controller method but shouldn't it be AppleLoginConfig in line 108 instead of GoogleLoginConfig

internal suspend fun ComposeAuth.signInWithApple(idToken: String) {
val config = config.loginConfig["apple"] as? GoogleLoginConfig
supabaseClient.auth.signInWith(IDToken) {
provider = Apple
this.idToken = idToken
nonce = config?.nonce
data = config?.extraData
}
}

AppleLoginConfig is defined here

data class AppleLoginConfig(
override val serverClientId: String = "",
val nonce: String? = null,
var extraData: JsonObject? = null
) : LoginConfig

@Vaibhav-214
Copy link

udpate: The control flow is going inside the authorizationController method but the two methods inside it are not executing

internal fun ComposeAuth.authorizationController(
scope:CoroutineScope,
onResult: (NativeSignInResult) -> Unit
): ASAuthorizationControllerDelegateProtocol {
return object : NSObject(), ASAuthorizationControllerDelegateProtocol {
override fun authorizationController(
controller: ASAuthorizationController,
didCompleteWithAuthorization: ASAuthorization
) {
try {
val credentials =
didCompleteWithAuthorization.credential as? ASAuthorizationAppleIDCredential
credentials?.identityToken?.base64EncodedStringWithOptions(
NSUTF8StringEncoding
)?.let { idToken ->
scope.launch {
signInWithApple(idToken)
onResult.invoke(NativeSignInResult.Success)
}
}
} catch (e: Exception) {
onResult.invoke(NativeSignInResult.Error(e.message ?: "error"))
}
}
override fun authorizationController(
controller: ASAuthorizationController,
didCompleteWithError: NSError
) {
when (didCompleteWithError.code.toUInt()) {
1001.toUInt() -> onResult.invoke(NativeSignInResult.ClosedByUser)
else -> onResult.invoke(NativeSignInResult.Error(didCompleteWithError.localizedDescription))
}
}
}
}

Here any of the two methods one at line 82 and another at line 102 is never executed throughout the process, I added print statments at the top and before the return statement by declaring the object as variable , it is printing all the statments that are outside the object methods and returning the delegate object too.But probably those methods are not triggered when they should be

@jan-tennert
Copy link
Collaborator Author

Yea, once we found a solution for this we definitely have to clean up the code a little bit

@sigmadeltasoftware
Copy link

Hey all,

Currently in progress of migrating from Firebase auth to Supabase for easier authorization/user management, and ran into this issue as well. Logging in through Firebase went without issue, but using the Supabase SDK on emulator results in basically loss of state (log-in popup closes and no feedback/error logging/ whatever is provided); And on a physical device it seems to crash with a BadRequestRestException.

Could it possibly be related to this error & fix which was reported somewhere around the same time:
supabase/auth#1401 (comment)

@Deorigami
Copy link

Hi i got this issue too,
With same codebase, My Android went smoothly but on ios

auth.sessionStatus.onEach {
            Napier.d(tag = "ANGGATAG", message = "Session Status : $it")
            when(it){
                is SessionStatus.Authenticated -> router.navigateToDashboard()
                SessionStatus.LoadingFromStorage -> Unit
                SessionStatus.NetworkError -> Unit
                is SessionStatus.NotAuthenticated -> Unit
            }}
.launchIn(screenModelScope)

even after success and i also check the auth log on supabase dashboard .. the status never change to anything

@yannickpulver
Copy link

As a workaround, it's possible to build the SignInWithApple button directly with SwiftUI, do the sign in natively in Swift and then import the Auth Session to the Kotlin instance. Its a rather hacky solution, but seems to work in my tests.

I made a gist you can find here:
https://gist.github.com/yannickpulver/f123ea210eef83757a0bc1bac9e83a28

To make this work, you will need to import Supabase Authentication in the XCode project (see docs for Supabase with Swift).

@Deorigami
Copy link

im using supabase so i dont do these kind of things :D

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

No branches or pull requests

5 participants