Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions auth/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ If using Facebook Login, add your Facebook App ID to `strings.xml`:
<resources>
<string name="facebook_application_id" translatable="false">YOUR_FACEBOOK_APP_ID</string>
<string name="facebook_login_protocol_scheme" translatable="false">fbYOUR_FACEBOOK_APP_ID</string>
<string name="facebook_client_token" translatable="false">CHANGE-ME</string>
</resources>
```

Expand Down Expand Up @@ -489,9 +490,6 @@ Configure Facebook Login with optional permissions:

```kotlin
val facebookProvider = AuthProvider.Facebook(
// Optional: Facebook application ID (reads from strings.xml if not provided)
applicationId = "YOUR_FACEBOOK_APP_ID",

// Optional: Permissions to request (default: ["email", "public_profile"])
scopes = listOf("email", "public_profile", "user_friends"),

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -485,7 +485,7 @@ abstract class AuthProvider(open val providerId: String, open val providerName:
/**
* The OAuth 2.0 client ID for your server.
*/
val serverClientId: String?,
var serverClientId: String?,

/**
* A map of custom OAuth parameters.
Expand All @@ -505,8 +505,9 @@ abstract class AuthProvider(open val providerId: String, open val providerName:
" default_web_client_id string wasn't populated.",
R.string.default_web_client_id
)
serverClientId = context.getString(R.string.default_web_client_id)
} else {
require(serverClientId.isNotBlank()) {
require(serverClientId!!.isNotBlank()) {
"Server client ID cannot be blank."
}
}
Expand All @@ -529,7 +530,7 @@ abstract class AuthProvider(open val providerId: String, open val providerName:
val credential: AuthCredential,
val idToken: String,
val displayName: String?,
val photoUrl: Uri?
val photoUrl: Uri?,
)

/**
Expand Down Expand Up @@ -567,7 +568,7 @@ abstract class AuthProvider(open val providerId: String, open val providerName:
credentialManager: CredentialManager,
serverClientId: String,
filterByAuthorizedAccounts: Boolean,
autoSelectEnabled: Boolean
autoSelectEnabled: Boolean,
): GoogleSignInResult

suspend fun clearCredentialState(
Expand Down Expand Up @@ -600,8 +601,10 @@ abstract class AuthProvider(open val providerId: String, open val providerName:
.build()

val result = credentialManager.getCredential(context, request)
val googleIdTokenCredential = GoogleIdTokenCredential.createFrom(result.credential.data)
val credential = GoogleAuthProvider.getCredential(googleIdTokenCredential.idToken, null)
val googleIdTokenCredential =
GoogleIdTokenCredential.createFrom(result.credential.data)
val credential =
GoogleAuthProvider.getCredential(googleIdTokenCredential.idToken, null)

return GoogleSignInResult(
credential = credential,
Expand All @@ -624,11 +627,6 @@ abstract class AuthProvider(open val providerId: String, open val providerName:
* Facebook Login provider configuration.
*/
class Facebook(
/**
* The Facebook application ID.
*/
val applicationId: String? = null,

/**
* The list of scopes (permissions) to request. Defaults to email and public_profile.
*/
Expand All @@ -653,18 +651,26 @@ abstract class AuthProvider(open val providerId: String, open val providerName:
)
}

if (applicationId == null) {
Preconditions.checkConfigured(
context,
"Facebook provider unconfigured. Make sure to " +
"add a `facebook_application_id` string or provide applicationId parameter.",
R.string.facebook_application_id
)
} else {
require(applicationId.isNotBlank()) {
"Facebook application ID cannot be blank"
}
}
Preconditions.checkConfigured(
context,
"Facebook provider unconfigured. Make sure to " +
"add a `facebook_application_id` string to your strings.xml",
R.string.facebook_application_id
)

Preconditions.checkConfigured(
context,
"Facebook provider unconfigured. Make sure to " +
"add a `facebook_login_protocol_scheme` string to your strings.xml",
R.string.facebook_login_protocol_scheme
)

Preconditions.checkConfigured(
context,
"Facebook provider unconfigured. Make sure to " +
"add a `facebook_client_token` string to your strings.xml",
R.string.facebook_client_token
)
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -294,12 +294,13 @@ class AuthUIConfigurationTest {
}

@Test
@Config(manifest = Config.NONE, qualifiers = "night")
fun `validation accepts all supported providers`() {
val config = authUIConfiguration {
context = applicationContext
providers {
provider(AuthProvider.Google(scopes = listOf(), serverClientId = "test_client_id"))
provider(AuthProvider.Facebook(applicationId = "test_app_id"))
provider(AuthProvider.Facebook())
provider(AuthProvider.Twitter(customParameters = mapOf()))
provider(AuthProvider.Github(customParameters = mapOf()))
provider(AuthProvider.Microsoft(customParameters = mapOf(), tenant = null))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package com.firebase.ui.auth.configuration.auth_provider

import android.content.Context
import androidx.test.core.app.ApplicationProvider
import com.firebase.ui.auth.R
import com.google.common.truth.Truth.assertThat
import com.google.firebase.auth.actionCodeSettings
import org.junit.Before
Expand Down Expand Up @@ -264,32 +265,34 @@ class AuthProviderTest {
}
}

@Test
@Config(manifest = Config.NONE, qualifiers = "night")
fun `google provider assigns default_web_client_id to serverClientId when null`() {
val provider = AuthProvider.Google(
scopes = listOf("email"),
serverClientId = null
)

provider.validate(applicationContext)

assertThat(provider.serverClientId)
.isEqualTo(applicationContext.getString(R.string.default_web_client_id))
}

// =============================================================================================
// Facebook Provider Tests
// =============================================================================================

@Test
@Config(manifest = Config.NONE, qualifiers = "night")
fun `facebook provider with valid configuration should succeed`() {
val provider = AuthProvider.Facebook(applicationId = "application_id")
val provider = AuthProvider.Facebook()

provider.validate(applicationContext)
}

@Test
fun `facebook provider with empty application id throws`() {
val provider = AuthProvider.Facebook(applicationId = "")

try {
provider.validate(applicationContext)
assertThat(false).isTrue() // Should not reach here
} catch (e: Exception) {
assertThat(e).isInstanceOf(IllegalArgumentException::class.java)
assertThat(e.message).isEqualTo("Facebook application ID cannot be blank")
}
}

@Test
fun `facebook provider validates facebook_application_id when applicationId is null`() {
fun `facebook provider validates facebook_application_id`() {
val provider = AuthProvider.Facebook()

try {
Expand All @@ -299,7 +302,7 @@ class AuthProviderTest {
assertThat(e).isInstanceOf(IllegalStateException::class.java)
assertThat(e.message).isEqualTo(
"Facebook provider unconfigured. Make sure to " +
"add a `facebook_application_id` string or provide applicationId parameter."
"add a `facebook_application_id` string to your strings.xml"
)
}
}
Expand Down Expand Up @@ -400,4 +403,4 @@ class AuthProviderTest {
assertThat(e.message).isEqualTo("Button label cannot be null or empty")
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ class FacebookAuthProviderFirebaseAuthUITest {
}

@Test
@Config(manifest = Config.NONE, qualifiers = "night")
fun `signInWithFacebook - successful sign in signs user in and emits Success authState`() = runTest {
val authStateListeners = mutableListOf<AuthStateListener>()
doAnswer { invocation ->
Expand All @@ -118,9 +119,7 @@ class FacebookAuthProviderFirebaseAuthUITest {
whenever(mockFirebaseAuth.currentUser).thenReturn(null)

val instance = FirebaseAuthUI.create(firebaseApp, mockFirebaseAuth)
val provider = spy(AuthProvider.Facebook(
applicationId = "000000000000"
))
val provider = spy(AuthProvider.Facebook())
val config = authUIConfiguration {
context = applicationContext
providers {
Expand Down Expand Up @@ -175,6 +174,7 @@ class FacebookAuthProviderFirebaseAuthUITest {
}

@Test
@Config(manifest = Config.NONE, qualifiers = "night")
fun `signInWithFacebook - handles account collision by saving credential and emitting error`() = runTest {
EmailLinkPersistenceManager.default.clear(applicationContext)
EmailLinkPersistenceManager.default.saveEmail(
Expand All @@ -185,9 +185,7 @@ class FacebookAuthProviderFirebaseAuthUITest {
)

val instance = FirebaseAuthUI.create(firebaseApp, mockFirebaseAuth)
val provider = spy(AuthProvider.Facebook(
applicationId = "000000000000"
))
val provider = spy(AuthProvider.Facebook())
val config = authUIConfiguration {
context = applicationContext
providers {
Expand Down Expand Up @@ -238,11 +236,10 @@ class FacebookAuthProviderFirebaseAuthUITest {
}

@Test
@Config(manifest = Config.NONE, qualifiers = "night")
fun `signInWithFacebook - converts FacebookException into AuthException`() = runTest {
val instance = FirebaseAuthUI.create(firebaseApp, mockFirebaseAuth)
val provider = spy(AuthProvider.Facebook(
applicationId = "000000000000"
))
val provider = spy(AuthProvider.Facebook())
val config = authUIConfiguration {
context = applicationContext
providers {
Expand Down
7 changes: 7 additions & 0 deletions auth/src/test/res/values-night/config.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="default_web_client_id" translatable="false">test_client_id</string>
<string name="facebook_application_id" translatable="false">test_app_id</string>
<string name="facebook_login_protocol_scheme" translatable="false">test_login_scheme</string>
<string name="facebook_client_token" translatable="false">test_client_token</string>
</resources>