How to get responded JWT in Unity Firebase Authentication? - firebase

as a newbie in Unity and C#, I am using Firebase email authentication in my project. I want to take an action with using responded JWT token. Here are my related codes:
private IEnumerator Login(string _email, string _password)
{
//Call the Firebase auth signin function passing the email and password
var LoginTask = auth.SignInWithEmailAndPasswordAsync(_email, _password);
//Wait until the task completes
yield return new WaitUntil(predicate: () => LoginTask.IsCompleted);
.
.
.
else
{
//User is now logged in
//Now get the result
User = LoginTask.Result;
Debug.LogFormat("User signed in successfully: {0} ({1})", User.DisplayName, User.Email);
warningLoginText.text = "";
confirmLoginText.text = "Logged In";
}
}
I think I need to access it from LoginTask. However, I don't know how to get JWT. I will use it API request operations. Thank you for your help.

I went through something similar and hope this helps:
In order to get the JWT token from the Firebase Authentication response in Unity, you can use the User object returned by the SignInWithEmailAndPasswordAsync() method and access the User.Token property.
JWT token:
private IEnumerator Login(string _email, string _password)
{
//Call the Firebase auth signin function passing the email and password
var LoginTask = auth.SignInWithEmailAndPasswordAsync(_email, _password);
//Wait until the task completes
yield return new WaitUntil(predicate: () => LoginTask.IsCompleted);
if (LoginTask.IsFaulted)
{
//Handle error
Debug.LogError("Error logging in user: " + LoginTask.Exception);
}
else
{
//User is now logged in
//Now get the result
User = LoginTask.Result;
Debug.LogFormat("User signed in successfully: {0} ({1})", User.DisplayName, User.Email);
warningLoginText.text = "";
confirmLoginText.text = "Logged In";
// Get the JWT token
string jwt = User.Token;
Debug.LogFormat("JWT token: {0}", jwt);
// Do something with the JWT token, such as sending it to a server for verification
}
}
It's worth noting that the token's lifetime is 1 hour, after which you will have to refresh it.

Related

AcquireToken stop working after some time

I am working in Xamarin forms application.
I am using below code snippet to get token for AAD sign-in.
IEnumerable<IAccount> accounts = await App.PCA.GetAccountsAsync().ConfigureAwait(false);
try
{
if (btnSignInSignOut.Text == "Sign in")
{
try
{
IAccount firstAccount = accounts.FirstOrDefault();
authResult = await App.PCA.AcquireTokenSilent(App.Scopes, firstAccount)
.ExecuteAsync()
.ConfigureAwait(false);
}
catch (MsalUiRequiredException)
{
try
{
var builder = App.PCA.AcquireTokenInteractive(App.Scopes)
.WithParentActivityOrWindow(App.ParentWindow);
if (Device.RuntimePlatform != "UWP")
{
// on Android and iOS, prefer to use the system browser, which does not exist on UWP
SystemWebViewOptions systemWebViewOptions = new SystemWebViewOptions()
{
iOSHidePrivacyPrompt = true,
};
builder.WithSystemWebViewOptions(systemWebViewOptions);
builder.WithUseEmbeddedWebView(false);
}
authResult = await builder.ExecuteAsync().ConfigureAwait(false);
}
catch (Exception ex2)
{
await DisplayAlert("Acquire token interactive failed. See exception message for details: ", ex2.Message, "Dismiss");
}
}
if (authResult != null)
{
var content = await GetHttpContentWithTokenAsync(authResult.AccessToken);
UpdateUserContent(content);
}
}
else
{
while (accounts.Any())
{
await App.PCA.RemoveAsync(accounts.FirstOrDefault()).ConfigureAwait(false);
accounts = await App.PCA.GetAccountsAsync().ConfigureAwait(false);
}
Device.BeginInvokeOnMainThread(() =>
{
slUser.IsVisible = false;
btnSignInSignOut.Text = "Sign in";
});
}
}
catch (Exception ex)
{
await DisplayAlert("Authentication failed. See exception message for details: ", ex.Message, "Dismiss");
}
But after some time, token expires somehow and not refresh. Due to that it always redirect user to MS login page.
My requirement is, It should automatically take the logged in user's details.
You can take reference from this code.
I have also check other options like to directly call api to get refresh token but didn't found anything helpful.
Let me know if anyone have any idea about it.
Thanks in Advance.
For now, MSAL already caches your authorization and can log you in silently if it’s still valid. So, as a user, you don’t need to sign in every time you use the app.
You could use SecureStorage.SetAsync to store the access token.
Sign-in:
public async Task<bool> SignInAsync()
{
try
{
var accounts = await _pca.GetAccountsAsync();
var firstAccount = accounts.FirstOrDefault();
var authResult = await _pca.AcquireTokenSilent(Scopes, firstAccount).ExecuteAsync();
// Store the access token securely for later use.
await SecureStorage.SetAsync("AccessToken", authResult?.AccessToken);
return true;
}
catch (MsalUiRequiredException)
{
try
{
// This means we need to login again through the MSAL window.
var authResult = await _pca.AcquireTokenInteractive(Scopes)
.WithParentActivityOrWindow(ParentWindow)
.ExecuteAsync();
// Store the access token securely for later use.
await SecureStorage.SetAsync("AccessToken", authResult?.AccessToken);
return true;
}
catch (Exception ex2)
{
Debug.WriteLine(ex2.ToString());
return false;
}
}
catch (Exception ex)
{
Debug.WriteLine(ex.ToString());
return false;
}
}
Just for clarification, MSAL does not return, issue the token, and does not expire the token. When your token expireS then MSAL will automatically refresh your token when calling the AcquireTokenSilentAsync (so you don't have to refresh your token). The reason why your application is redirecting to the login page is because when you call the authenticated API then this API is returning the response 401 (Unauthorized) which means while calling the API you are not sending the token with the request. In return when the server returns 401 (Unauthorized) response, then your application is redirecting the user to the login page.
Read more about MSAL token expiration here.
Update your code accordingly:
await SecureStorage.SetAsync("accessToken", authResult.AccessToken);

facebookAuthCredential.idToken is null in Flutter

I successfully integrated facebook login in android and ios, I also getting facebook access token on login but getting null in token id. Below is the code
Future<UserCredential> signInWithFacebook() async {
// Trigger the sign-in flow
final LoginResult loginResult = await FacebookAuth.instance.login();
// Create a credential from the access token
final OAuthCredential facebookAuthCredential =
FacebookAuthProvider.credential(loginResult.accessToken!.token);
print(facebookAuthCredential.idToken); //Here getting null
// Once signed in, return the UserCredential
return FirebaseAuth.instance.signInWithCredential(facebookAuthCredential);
}
You won't get an idToken at this point with Facebook authentication flow, only accessToken. Use the following code skeleton to manage Facebook sign-in and evaluate the results at specific lines with breakpoints:
Future<UserCredential> signInWithFacebook() async {
final LoginResult loginResult = await FacebookAuth.instance.login();
if (loginResult.status == LoginStatus.success) {
final AccessToken accessToken = loginResult.accessToken!;
final OAuthCredential credential =
FacebookAuthProvider.credential(accessToken.token);
try {
return await FirebaseAuth.instance.signInWithCredential(credential);
} on FirebaseAuthException catch (e) {
// manage Firebase authentication exceptions
} catch (e) {
// manage other exceptions
}
} else {
// login was not successful, for example user cancelled the process
}
}
Then you can call this function with await, and once the future is completed, you can access user data:
final userCredential = await signInWithFacebook();
if (userCredential != null) {
// here you will have your Firebase user in:
// userCredential.user
final idToken = userCredential.user!.getIdToken();
}

How to sign up and in with OAuth credentials in firebase and flutter?

I was reading in the firebase Auth Rest Api and found this OAuth Credentials that contains a lot of information about a user that signs in including if the email is verified, So I tried to do it in my flutter app but looks like I am missing sth called Request URI I am new to flutter and firebase so I need your help.
My code:
static Future signin(String email, String password) async {
try {
http.Response response = await http.post(
'https://identitytoolkit.googleapis.com/v1/accounts:signInWithIdp?key=AIzaSyD3KOx9KSfK1lhyWRCt4_-dXLkKDNq-0hU',
body: {
'email': email,
'password': password,
'requestUri': ?? 'Sth of Type String',
},
);
if (response.statusCode == 200) {
print(response.statusCode);
print(json.decode(response.body));
} else {
print(response.statusCode);
}
String jsonsDataString = response.body.toString();
var _data = jsonDecode(jsonsDataString);
print(_data.toString());
print({email, password});
if (response.body.contains('EMAIL_EXISTS')) {
print('email exists');
} else if (response.body.contains('WEAK_PASSWORD')) {
print('weak password');
}
} catch (e) {
print(e);
}
}
Your are using the API for signing in with via oAuth and the requestUri ist the redirect URL of the auth flow.
Check this link: https://www.oauth.com/oauth2-servers/redirect-uris/
What you could do is use the sign-in with email api instead.
Check https://firebase.google.com/docs/reference/rest/auth and search sign in with email / passwort.

How to use timer in flutter app for changing data?

I am using shared preferences to store the token, email, username and other user details when a user logs in using firebase authentication. The firebase token expires in every one hour so I need to refresh the token on the basis of when the user has returned to the app which I am doing in getCurrentUser() function below. I want to know that if a user has logged in my app, used it for 5 minutes or so and then close the application, will that timer function would still be listening and call the function after the timeout or not?
If it doesn't do so then How can I achieve checking this?
void checkTokenValidity(int time) {
Timer(Duration(seconds: time), () async {
print('token timed out');
SharedPreferences prefs = await SharedPreferences.getInstance();
prefs.setString('token', 'expired');
prefs.remove("currentUser");
});
}
Future<String> getCurrentUser() async {
final SharedPreferences prefs = await SharedPreferences.getInstance();
final String currentToken = prefs.getString('token');
final String cuser = prefs.getString('currentUser');
print("current: $cuser");
if (cuser != null && currentToken != 'expired') {
print('signed in and $currentToken');
SharedPreferences prefs = await SharedPreferences.getInstance();
String token = prefs.getString('token');
String uid = prefs.getString('userId');
String email = prefs.getString('userEmail');
String photo = prefs.getString('photo');
_authenticatedUser =
User(email: email, id: uid, token: token, photo: photo);
return 'success';
} else if (currentToken == 'expired') {
print('token is expired');
final FirebaseUser user = await FirebaseAuth.instance.signInAnonymously();
var token = await user.getIdToken();
prefs.setString('token', token);
String uid = prefs.getString('userId');
String email = prefs.getString('userEmail');
String photo = prefs.getString('photo');
_authenticatedUser =
User(id: uid, email: email, token: token, photo: photo);
checkTokenValidity(3600);
return 'token';
} else {
print('user is null');
return null;
}
}
In my authentication function which is not here, I have called checkTokenValidity(3600) just after the user successfully logs in.
I have also tried using FirebaseUser user = await FirebaseAuth.instance.currentUser(); but that also didn't solve the problem.
You went the wrong way. The right way is to add error handler on 401 (Unauthorized) error and handle it by refreshing token and retrying the same query.

Firebase confirmation email not being sent

I've set up Firebase email/password authentication successfully, but for security reasons I want the user to confirm her/his email.
It says on Firebases website:
When a user signs up using an email address and password, a confirmation email is sent to verify their email address.
But when I sign up, I doesn't receive a confirmation email.
I've looked and can only find a code for sending the password reset email, but not a code for sending the email confirmation.
I've looked here:
https://firebase.google.com/docs/auth/ios/manage-users#send_a_password_reset_email
anyone got a clue about how I can do it?
I noticed that the new Firebase email authentication docs is not properly documented.
firebase.auth().onAuthStateChanged(function(user) {
user.sendEmailVerification();
});
Do note that:
You can only send email verification to users object whom you created using Email&Password method createUserWithEmailAndPassword
Only after you signed users into authenticated state, Firebase will return a promise of the auth object.
The old onAuth method has been changed to onAuthStateChanged.
To check if email is verified:
firebase.auth().onAuthStateChanged(function(user) {
if (user.emailVerified) {
console.log('Email is verified');
}
else {
console.log('Email is not verified');
}
});
After creating a user a User object is returned, where you can check if the user's email has been verified or not.
When a user has not been verified you can trigger the sendEmailVerification method on the user object itself.
firebase.auth()
.createUserWithEmailAndPassword(email, password)
.then(function(user){
if(user && user.emailVerified === false){
user.sendEmailVerification().then(function(){
console.log("email verification sent to user");
});
}
}).catch(function(error) {
// Handle Errors here.
var errorCode = error.code;
var errorMessage = error.message;
console.log(errorCode, errorMessage);
});
You can also check by listening to the AuthState, the problem with the following method is, that with each new session (by refreshing the page),
a new email is sent.
firebase.auth().onAuthStateChanged(function(user) {
user.sendEmailVerification();
});
The confirmation email could be in your spam folder.
Check your spam folder.
You can send verification email and check if was verified as follow into the AuthListener:
mAuthListener = new FirebaseAuth.AuthStateListener() {
#Override
public void onAuthStateChanged(#NonNull FirebaseAuth firebaseAuth) {
FirebaseUser user = firebaseAuth.getCurrentUser();
if (user != null) {
//---- HERE YOU CHECK IF EMAIL IS VERIFIED
if (user.isEmailVerified()) {
Toast.makeText(LoginActivity.this,"You are in =)",Toast.LENGTH_LONG).show();
}
else {
//---- HERE YOU SEND THE EMAIL
user.sendEmailVerification();
Toast.makeText(LoginActivity.this,"Check your email first...",Toast.LENGTH_LONG).show();
}
} else {
// User is signed out
Log.d(TAG, "onAuthStateChanged:signed_out");
}
// [START_EXCLUDE]
updateUI(user);
// [END_EXCLUDE]
}
};
if you're using compile "com.google.firebase:firebase-auth:9.2.0" and
compile 'com.google.firebase:firebase-core:9.2.0' the method sendEmailVerification() will not be resolved until you update to 9.8.0 or higher. It wasted most of time before I figured it out.
I have been looking at this too. It seems like firebase have changed the way you send the verification. for me
user.sendEmailVerification()
did not work.
If you get an error such as user.sendEmailVerification() doesn't exist.
use the following.
firebase.auth().currentUser.sendEmailVerification()
It's not the answer to the question but might help someone.
Don't forget to add your site domain to the Authorised domains list under Sign-in-method
You could send a verification email to any user whose email is linked to the Firebase Auth account. For example, in Flutter you could do. something like :
Future<void> signInWithCredentialAndLinkDetails(AuthCredential authCredential,
String email, String password) async {
// Here authCredential is from Phone Auth
_auth.signInWithCredential(authCredential).then((authResult) async {
if (authResult.user != null) {
var emailAuthCredential = EmailAuthProvider.getCredential(
email: email,
password: password,
);
authResult.user
.linkWithCredential(emailAuthCredential)
.then((authResult,onError:(){/* Error Logic */}) async {
if (authResult.user != null) {
await authResult.user.sendEmailVerification().then((_) {
debugPrint('verification email send');
}, onError: () {
debugPrint('email verification failed.');
});
}
});
}
});
}

Resources