Firebase phone auth kotlin wont send verification code - android

I am trying to use firebase phone auth in my
app with an emulator. I have a testing number set up in firebase, but everytime i try to send a verification code, I get the same error: PhoneAuthProvider: Sms auto retrieval timed-out. how do i fix this?*
class PhoneAuth : AppCompatActivity() {
private var verificationIdGlobal: String? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_phone_auth)
b_phone_send.setOnClickListener {
val phoneNumber = et_phone_phone.text.toString().trim()
PhoneAuthProvider.getInstance().verifyPhoneNumber(
phoneNumber, // Phone number to verify
60, // Timeout duration
TimeUnit.SECONDS, // Unit of timeout
this, // Activity (for callback binding)
callbacks) // OnVerificationStateChangedCallbacks
}
b_phone_sign_in.setOnClickListener {
val verificationCode = et_phone_verification_code.text.toString().trim()
verificationIdGlobal?.let {
val credential = PhoneAuthProvider.getCredential(it, verificationCode)
addPhoneNumber(credential)
}
}}
private val callbacks = object : PhoneAuthProvider.OnVerificationStateChangedCallbacks(){
override fun onVerificationCompleted(phoneAuthCredential: PhoneAuthCredential) {
phoneAuthCredential.let {
addPhoneNumber(phoneAuthCredential)
}
TODO("Not yet implemented")
}
override fun onVerificationFailed(exception: FirebaseException) {
Log.d("phone", "$exception")
TODO("Not yet implemented")
}
override fun onCodeSent(verificationId: String, token: PhoneAuthProvider.ForceResendingToken) {
super.onCodeSent(verificationId, token)
verificationIdGlobal = verificationId
}
}
private fun addPhoneNumber(phoneAuthCredential: PhoneAuthCredential){
FirebaseAuth.getInstance().currentUser?.updatePhoneNumber(phoneAuthCredential)?.addOnCompleteListener {task ->
if (task.isSuccessful){
Log.d("Phone", "task successful")
}
else{
Log.d("Phone", "${task.exception}")
}
}
}

as per my understanding, if you added a phone number as a test number in Firebase console then it will never send a SMS to it, if you did so, then make sure you remove the number from test numbers list in firebase console >> Authentication >> Sign-in method >> Phone >> Phone numbers for testing, then try sending verification SMS to it.

You need to disable developer options and restart your smartphone. Now collect the project and install it on your smartphone, you will receive SMS.

Related

Android : How to generate OTP for input field that takes email or phone number using firebase

I have created signup page in Android that has input field which takes email or phone number
, after signup it should receive OTP for the respective input.I have done OTP verification for phone number.My question is my input field accepts either email or phone number. How do I make OTP verification in that case ?
this is the signup activity
package com.example.memorybus
import android.content.ContentValues.TAG
import android.content.Intent
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import android.widget.Button
import android.widget.EditText
import android.widget.Toast
import com.example.memorybus.databinding.ActivitySignUpBinding
import com.google.firebase.FirebaseException
import com.google.firebase.FirebaseTooManyRequestsException
import com.google.firebase.auth.*
import java.util.concurrent.TimeUnit
class SignUp : AppCompatActivity() {
private lateinit var firebaseAuth: FirebaseAuth
private lateinit var binding: ActivitySignUpBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivitySignUpBinding.inflate(layoutInflater)
setContentView(binding.root)
firebaseAuth = FirebaseAuth.getInstance()
binding.textview.setOnClickListener {
val intent = Intent(this, Login::class.java)
startActivity(intent)
}
binding.btnSignup.setOnClickListener {
val name = binding.name.text.toString()
val email_ph = binding.emailPhone.text.toString()
val relation = binding.relation.text.toString()
val password = binding.passwordSignup.text.toString()
if (email_ph.isNotEmpty())
{
val options = PhoneAuthOptions.newBuilder(firebaseAuth)
.setPhoneNumber(email_ph) // Phone number to verify
.setTimeout(60L, TimeUnit.SECONDS) // Timeout and unit
.setActivity(this) // Activity (for callback binding)
.setCallbacks(callbacks) // OnVerificationStateChangedCallbacks
.build()
PhoneAuthProvider.verifyPhoneNumber(options)
}
else
{
Toast.makeText(this,"Please enter the fields",Toast.LENGTH_SHORT).show()
}
}
}
private fun signInWithPhoneAuthCredential(credential: PhoneAuthCredential) {
firebaseAuth.signInWithCredential(credential)
.addOnCompleteListener(this) { task ->
if (task.isSuccessful) {
// Sign in success, update UI with the signed-in user's information
//Log.d(TAG, "signInWithCredential:success")
sendToLogin()
val user = task.result?.user
} else {
// Sign in failed, display a message and update the UI
Log.w(TAG, "signInWithCredential:failure", task.exception)
if (task.exception is FirebaseAuthInvalidCredentialsException) {
// The verification code entered was invalid
}
// Update UI
}
}
}
private fun sendToLogin()
{
startActivity(Intent(this,Login::class.java))
}
private val callbacks = object : PhoneAuthProvider.OnVerificationStateChangedCallbacks() {
override fun onVerificationCompleted(credential: PhoneAuthCredential) {
// This callback will be invoked in two situations:
// 1 - Instant verification. In some cases the phone number can be instantly
// verified without needing to send or enter a verification code.
// 2 - Auto-retrieval. On some devices Google Play services can automatically
// detect the incoming verification SMS and perform verification without
// user action.
//Log.d(TAG, "onVerificationCompleted:$credential")
signInWithPhoneAuthCredential(credential)
}
override fun onVerificationFailed(e: FirebaseException) {
// This callback is invoked in an invalid request for verification is made,
// for instance if the the phone number format is not valid.
// Log.w(TAG, "onVerificationFailed", e)
if (e is FirebaseAuthInvalidCredentialsException) {
// Invalid request
Log.w(TAG, "onVerificationFailed", e)
} else if (e is FirebaseTooManyRequestsException) {
// The SMS quota for the project has been exceeded
Log.w(TAG, "onVerificationFailed", e)
}
// Show a message and update the UI
}
override fun onCodeSent(
verificationId: String,
token: PhoneAuthProvider.ForceResendingToken
) {
// The SMS verification code has been sent to the provided phone number, we
// now need to ask the user to enter the code and then construct a credential
// by combining the code with a verification ID.
// Log.d(TAG, "onCodeSent:$verificationId")
// Save verification ID and resending token so we can use them later
val intent = Intent(this#SignUp,OTP::class.java)
intent.putExtra("OTP", verificationId)
startActivity(intent)
/* storedVerificationId = verificationId
resendToken = token*/
}
}
}
Firebase Authentication support OTP based authentication for phone numbers only. The email equivalent would be to use email link sign in.
Once user enters their credentials, check if it is a valid email or phone number and call the relevant function.
If you want to use OTPs only then you'll have to build your own solution using Cloud Function similar to this post.

1v1 video chat using token authentication in agora.io for android

I am trying to implement 1v1 video chat in my android app using token based authentication. I can generate the token and use it in my app. But it is not working. I wonder that when I generate the token will I use 1 uid for the 2 user or will I use 2 different uid for the 2 user. If I use 1 uid and then will I use the same token for this 2 user. if I use 2 uid and then 2 different token is being created for this 2 user. I can not solve this token based authentication. how does it work? can you help me please?
For example, 1 user is trying to make a video call. I can generate token using this user's uid. When the other user join this video call, will the second user use the same token or the second user will generate another token using its uid. I am confusied in this part. how the second user will join the call? thanks
My code for video call:
class VideoCallActivity : AppCompatActivity() {
private val db = Firebase.firestore
// Kotlin
// Fill the App ID of your project generated on Agora Console.
private val APP_ID = "app_id"
// Fill the channel name.
private val CHANNEL = "appointment"
private var TOKEN =
private var mRtcEngine: RtcEngine? = null
private lateinit var localContainer: FrameLayout
private lateinit var remoteContainer: FrameLayout
private var uniqueUserUidLocal: Int = 0
private var uniqueUserUidRemote: Int = 0
private val mRtcEventHandler = object : IRtcEngineEventHandler() {
// Listen for the remote user joining the channel to get the uid of the user.
override fun onUserJoined(uniqueUserUidRemote: Int, elapsed: Int) {
runOnUiThread {
// Call setupRemoteVideo to set the remote video view after getting uid from the onUserJoined callback.
setupRemoteVideo(uniqueUserUidRemote)
}
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_video_call)
localContainer = findViewById<FrameLayout>(R.id.local_video_view_container)
remoteContainer = findViewById<FrameLayout>(R.id.remote_video_view_container)
val userId = intent.getStringExtra("chaplainUniqueUserId").toString()
uniqueUserUidRemote = userId.toInt(10)
getToken()
//initializeAndJoinChannel()
video_page_finnish_call_imageButton.setOnClickListener {
mRtcEngine?.stopPreview()
mRtcEngine?.leaveChannel()
RtcEngine.destroy()
finish()
}
}
private fun getToken(){
//getting token info from rest api
val retrofit = Retrofit.Builder()
.baseUrl("https://kadir.webprogrammer.fi/")
.addConverterFactory(GsonConverterFactory.create())
.build()
val api = retrofit.create(TokenApiInterface::class.java)
//this part is not clear. which uid should be used remote uid or local uid
api.fetchAllData(uid = uniqueUserUidRemote.toString()).enqueue(object : Callback<TokenModelClass> {
override fun onResponse(
call: Call<TokenModelClass>,
response: Response<TokenModelClass>
) {
TOKEN = response.body()?.token ?: TOKEN
Log.e("TOKEN_1: ", TOKEN)
Log.e("TOKEN_2: ", uniqueUserUidRemote.toString())
initializeAndJoinChannel(TOKEN)
}
override fun onFailure(call: Call<TokenModelClass>, t: Throwable) {
Log.e("TOKEN: ", t.message.toString())
}
})
}
private fun initializeAndJoinChannel(TOKEN: String) {
try {
mRtcEngine = RtcEngine.create(baseContext, APP_ID, mRtcEventHandler)
} catch (e: Exception) {
}
// By default, video is disabled, and you need to call enableVideo to start a video stream.
mRtcEngine!!.enableVideo()
// Call CreateRendererView to create a SurfaceView object and add it as a child to the FrameLayout.
val localFrame = RtcEngine.CreateRendererView(baseContext)
localFrame.setZOrderMediaOverlay(true)
localContainer.addView(localFrame)
// Pass the SurfaceView object to Agora so that it renders the local video.
mRtcEngine!!.setupLocalVideo(VideoCanvas(localFrame, VideoCanvas.RENDER_MODE_FIT, 0))
//this uid is the local user uid, not the remote user uid
// Join the channel with a token.
mRtcEngine!!.joinChannel(TOKEN, CHANNEL, "", 0)
}
private fun setupRemoteVideo(uniqueUserUidRemote: Int) {
val remoteFrame = RtcEngine.CreateRendererView(baseContext)
//remoteFrame.setZOrderMediaOverlay(true)
remoteContainer.addView(remoteFrame)
mRtcEngine!!.setupRemoteVideo(
VideoCanvas(
remoteFrame,
VideoCanvas.RENDER_MODE_FIT,
uniqueUserUidRemote
)
)
}
override fun onDestroy() {
super.onDestroy()
mRtcEngine?.stopPreview()
mRtcEngine?.leaveChannel()
RtcEngine.destroy()
}
}
Every token that you generate is unique to a channel and UID. So when your app loads it should load the network request. Using the token returned from the token server you can call the joinChannel method, make sure you pass the same UID and channel name to the joinChannel parameter that you used while generating the token.
You can read more about it over here: https://www.agora.io/en/blog/connecting-to-agora-with-tokens-android/

SMS verification code request failed when authenticating using Firebase Auth

When authenticating using Firebase Auth, I want to auto input the code that is received via SMS. I am able to receive SMS and go through auth process manually, but when I use SmsRetriever, the app crashes and then the bottom sheet dialog shows up.
This is everything that that appears in Logcat:
E/FirebaseAuth: [SmsRetrieverHelper] SMS verification code request failed: unknown status code: 17010 null
Code in Fragment where user inputs their phone number:
private val SMS_CONSENT_REQUEST = 2 // Set to an unused request code
private val smsVerificationReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
if (SmsRetriever.SMS_RETRIEVED_ACTION == intent.action) {
val extras = intent.extras
val smsRetrieverStatus = extras?.get(SmsRetriever.EXTRA_STATUS) as Status
when (smsRetrieverStatus.statusCode) {
CommonStatusCodes.SUCCESS -> {
// Get consent intent
val consentIntent = extras.getParcelable<Intent>(SmsRetriever.EXTRA_CONSENT_INTENT)
try {
// Start activity to show consent dialog to user, activity must be started in
// 5 minutes, otherwise you'll receive another TIMEOUT intent
startActivityForResult(consentIntent, SMS_CONSENT_REQUEST)
} catch (e: ActivityNotFoundException) {
// Handle the exception ...
}
}
CommonStatusCodes.TIMEOUT -> {
// Time out occurred, handle the error.
}
}
}
}
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val task = SmsRetriever.getClient(requireActivity()).startSmsUserConsent(null)
val intentFilter = IntentFilter(SmsRetriever.SMS_RETRIEVED_ACTION)
requireActivity().registerReceiver(smsVerificationReceiver, intentFilter)
}
override fun sendSms() {
showProgressBar(true)
SmsRetriever.getClient(requireActivity()).startSmsUserConsent(presenter.getNumber())
val options = PhoneAuthOptions.newBuilder(auth)
.setPhoneNumber(presenter.getNumber())
.setTimeout(58L, TimeUnit.SECONDS)
.setActivity(requireActivity())
.setCallbacks(callbacks)
.build()
PhoneAuthProvider.verifyPhoneNumber(options)
}
override fun onDestroy() {
super.onDestroy()
requireContext().unregisterReceiver(smsVerificationReceiver)
}
This is the code in Fragment where user has to input the code:
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
when (requestCode) {
// ...
SMS_CONSENT_REQUEST ->
// Obtain the phone number from the result
if (resultCode == Activity.RESULT_OK && data != null) {
// Get SMS message content
val message = data.getStringExtra(SmsRetriever.EXTRA_SMS_MESSAGE)
// Extract one-time code from the message and complete verification
// `message` contains the entire text of the SMS message, so you will need
// to parse the string.
message?.let { presenter.parseSms(it) }
// send one time code to the server
} else {
// Consent denied. User can type OTC manually.
}
}
}
Print your FirebaseAuthException error to see what's going on. If you're using a real phone number for development and using it again and again, Firebase might block the device for a time being.
SOLUTION: Add a test phone number with a password and use it.
try to print exception in onFailure like --> {p0.message} print this line logcat and it will definately show --> E/exception in firebase: We have blocked all requests from this device due to unusual activity. Try again later. this is why because we are using this phone number many times for login
It is a too-many-request error screenshot
The solution is to either wait for few hours or -if this user is a test user- , just add the number in test users to fix the code and do not send too many SMSes.

Firebase OTP verification onVerificationCompleted not called

I'm trying to set up OTP verification so when the user enters their phone number, I send them a pin code, the onCodeSent() is called and I receive the code pin, but the problem is when onVerificationCompleted() is called, I would like to move to another activity where the user can enter the code pin to verify but it is not called at all and I don't understand why. Any help would be appreciated guys, thank you.
val auth = PhoneAuthOptions
.newBuilder(FirebaseAuth.getInstance())
.setPhoneNumber(phoneNumber)
.setTimeout(60L,TimeUnit.MILLISECONDS)
.setActivity(this)
.setCallbacks(object : PhoneAuthProvider.OnVerificationStateChangedCallbacks() {
override fun onVerificationCompleted(p0: PhoneAuthCredential) {
// here i want to get the smscode and send it over the next activity to verify
// but this method is not called at all
Intent(this,ChangePasswordActivity::class.java).apply {
putExtra("code",p0.smsCode)
startActivity(this)
}
}
override fun onVerificationFailed(p0: FirebaseException) {
Timber.d("Firebase Exception ${p0.message}")
}
override fun onCodeSent(code: String, p1: PhoneAuthProvider.ForceResendingToken) {
super.onCodeSent(code, p1)
}
override fun onCodeAutoRetrievalTimeOut(p0: String) {
super.onCodeAutoRetrievalTimeOut(p0)
}
})
.build()
PhoneAuthProvider.verifyPhoneNumber(auth)
onVerificationCompleted() will only be called when the phone number has been verified without any input from the user. To do what you are trying, you should be sending your intent inside onCodeSent() instead.
Here is a rough flow of events (that are covered in detail in the documentation):
Obtain phone number from user
Call PhoneAuthProvider.verifyPhoneNumber(auth) (as you are already) to send the pin to the user
onCodeSent() is called, with the verification ID and a resending token.
Inside of onCodeSent(), create an intent to launch the "pin input screen" with the verification ID.
Get a pin from the user and then combine it with the verification ID by calling PhoneAuthCredential credential = PhoneAuthProvider.getCredential(verificationId, userInput)
Use that credential to sign in the user using signInWithCredential(credential).
val auth = PhoneAuthOptions
.newBuilder(FirebaseAuth.getInstance())
.setPhoneNumber(phoneNumber)
.setTimeout(60L,TimeUnit.MILLISECONDS)
.setActivity(this)
.setCallbacks(object : PhoneAuthProvider.OnVerificationStateChangedCallbacks() {
override fun onVerificationCompleted(credential: PhoneAuthCredential) {
// if here, phone number was verified automatically
mAuth.signInWithCredential(credential)
.addOnCompleteListener(/* ... */)
}
override fun onVerificationFailed(p0: FirebaseException) {
Timber.d("Firebase Exception ${p0.message}")
}
override fun onCodeSent(verificationId: String, resendToken: PhoneAuthProvider.ForceResendingToken) {
// if here, code was sent to phone number
// open pin input screen
Intent(this,ChangePasswordActivity::class.java).apply {
putExtra("verificationId",verificationId)
startActivity(this)
}
}
// we aren't using onCodeAutoRetrievalTimeOut, so it's omitted.
})
.build()
PhoneAuthProvider.verifyPhoneNumber(auth)
I was also facing this problem but when I added my project to google cloud console, enable api services(google cloud console) and enable phone verification(google cloud console)
then onVerificationCompleted is working fine.
https://console.cloud.google.com/home

Android: AWS Amplify User State is not getting update

I have just started learning AWS Amplify and I am integrating it to my android project to authenticate users. I have successfully logged-in but UserState is still SIGNED_OUT.
AWSMobileClient.getInstance().signIn(userName, password, null, callback)
Callback Code snippet
fun fetchAuthenticationCallBack(): Callback<SignInResult> {
return object : Callback<SignInResult> {
override fun onResult(result: SignInResult?) {
when (result?.signInState) {
SignInState.DONE -> {
// AWSMobileClient.getInstance().confirmSignIn()
Log.d(TAG, "LOGIN SUCCESS ${AWSMobileClient.getInstance().tokens.accessToken}")
}
SignInState.NEW_PASSWORD_REQUIRED -> {
Log.d(TAG, "NEW PASSWORD CHALLENGE")
}
else -> {
// Unsupported sign-in confirmation:
}
}
}
override fun onError(e: java.lang.Exception?) {
TODO("Not yet implemented")
}
}
}
I want to get the accessToken but it gives me Exception
Token does not support retrieving while user is SIGN_OUT
Is there anything that I am missing in the authentication part?
If anyone will face this issue in the future.
Kindly check your awsconfiguration.json file there is something went wrong. In my case CognitoIdentity credentials were wrong. I have just fixed the awsconfiguration.json file everything is working as expected

Categories

Resources