i am developing an application that requires firebase custom tokens.
I can assign custom claims by callable cloud functions in node.js server. Now i need them in my app for controlling access. How can i achieve it?
FirebaseAuth.getInstance().getCurrentUser().getTokens()
like that
I have tried to get tokens from firestore but it costs read operations.
Use getIdToken() on Auth user to get claims.
Check out the below example:
user.getIdToken(false).addOnSuccessListener(new OnSuccessListener<GetTokenResult>() {
#Override
public void onSuccess(GetTokenResult result) {
boolean isAdmin = result.getClaims().get("admin");
if (isAdmin) {
// Show admin UI.
showAdminUI();
} else {
// Show regular user UI.
showRegularUI();
}
}
});
Also please keep in mind that ID Token need to be refreshed before these are updated which you can do by following,
currentUser.getIdToken(true)
And custom claims are only to verify roles and for storing very small data. It should not be used to keep user's information.
Source and Further Read: https://firebase.google.com/docs/auth/admin/custom-claims#propagate_custom_claims_to_the_client
currentUser has getIdToken method with a callback argument addOnSuccessListener. The addOnSuccessListener give access to GetTokenResult(map) use that to check your claims.
private fun login() {
val user = FirebaseAuth.getInstance().currentUser
if (user == null) showAuthActivity()
user?.getIdToken(true) // forceRefresh: boolean Force refresh regardless of token expiration.
?.addOnSuccessListener {it: GetTokenResult ->
val role = (it.claims["admin"] as? Boolean)
?: (it.claims["clientUser"] as? Boolean) ?: false
if (role) {
startActivity(Intent(this, MainActivity::class.java))
finish()
} else {
showAuthActivity()
showToast("You don't have permissions to use this app")
}
}
?.addOnFailureListener {
showAuthActivity()
showToast("Something went wrong e = ${it.message}")
}?.addOnCanceledListener {
showAuthActivity()
}
}
Related
I'm new with zoom integration.
I wants user login and create meeting in their account. I've done login user part using loginWithZoom method but now wants to create meeting for that auth token needed.
How can I get token when user login in zoom without OAuth?
I've found but not getting much idea. I tried with JWT token it works with
https://api.zoom.us/v2/users/me/meetings api. I gave Authorization token and content-type in
headers. it gives me all meetings of that specific user. but problem to get different authorization token for different users. I don't have idea is it possible or not.
Suggest if anyone knows
Code I've used for Login:
public void initializeSdk(Context context) {
ZoomSDK sdk = ZoomSDK.getInstance();
// TODO: Do not use hard-coded values for your key/secret in your app in production!
ZoomSDKInitParams params = new ZoomSDKInitParams();
params.appKey = "a...t4.."; // TODO: Retrieve your SDK key and enter it here
params.appSecret = "y...19"; // TODO: Retrieve your SDK secret and enter it here
params.domain = "zoom.us";
params.enableLog = true;
// TODO: Add functionality to this listener (e.g. logs for debugging)
ZoomSDKInitializeListener listener = new ZoomSDKInitializeListener() {
/**
* #param errorCode {#link us.zoom.sdk.ZoomError#ZOOM_ERROR_SUCCESS} if the SDK has been initialized successfully.
*/
#Override
public void onZoomSDKInitializeResult(int errorCode, int internalErrorCode) {
Log.i("","onZoomSDKInitializeResult Error code"+errorCode);
Toast.makeText(getApplicationContext()," error code : " + errorCode,Toast.LENGTH_LONG).show();
}
#Override
public void onZoomAuthIdentityExpired() {
System.out.println(" identity expired..");
}
};
sdk.initialize(context, listener, params);
}
findViewById(R.id.login_button).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Toast.makeText(getApplicationContext(), "onclick of login", Toast.LENGTH_LONG).show();
Log.i(" ","onclick of login : "+ ZoomSDK.getInstance().isLoggedIn());
if (ZoomSDK.getInstance().isLoggedIn()) {
//wants to create meeting
} else {
createLoginDialog();
}
}
});
private void createLoginDialog() {
new AlertDialog.Builder(this)
.setView(R.layout.dialog_login)
.setPositiveButton("Log in", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialogInterface, int i) {
AlertDialog dialog = (AlertDialog) dialogInterface;
TextInputEditText emailInput = dialog.findViewById(R.id.email_input);
TextInputEditText passwordInput = dialog.findViewById(R.id.pw_input);
if (emailInput != null && emailInput.getText() != null && passwordInput != null && passwordInput.getText() != null) {
String email = emailInput.getText().toString();
String password = passwordInput.getText().toString();
if (email.trim().length() > 0 && password.trim().length() > 0) {
login(email, password);
}
}
dialog.dismiss();
}
})
.show();
}
public void login(String username, String password) {
int result = ZoomSDK.getInstance().loginWithZoom(username, password);
if (result == ZoomApiError.ZOOM_API_ERROR_SUCCESS) {
// Request executed, listen for result to start meeting
ZoomSDK.getInstance().addAuthenticationListener(authListener);
}
}
public void onZoomSDKLoginResult(long result) {
if (result == ZoomAuthenticationError.ZOOM_AUTH_ERROR_SUCCESS) {
// Once we verify that the request was successful, we may start the meeting
Toast.makeText(getApplicationContext(), "Login successfully", Toast.LENGTH_SHORT).show();
} else if(result == ZoomAuthenticationError.ZOOM_AUTH_ERROR_USER_NOT_EXIST || result == ZoomAuthenticationError.ZOOM_AUTH_ERROR_WRONG_PASSWORD){
Toast.makeText(getApplicationContext(),"Invalid username or password",Toast.LENGTH_LONG).show();
}
}
Thanks in advance.
I tried with JWT token it works with
https://api.zoom.us/v2/users/me/meetings api. I gave Authorization
token and content-type in headers. it gives me all meetings of that
specific user. but problem to get different authorization token for
different users. I don't have idea is it possible or not.
Assuming these users are not part of the same Zoom account, then no, it is not possible as of 2021-08-28. JWT-based authentication is only for Zoom integration in internal applications/services:
Note: JWT may only be used for internal applications and processes. All apps created for third-party usage must use our OAuth app type.
In this context, "internal" means "only to be used with a single Zoom account." Note that there can be many users under one account (e.g., all employees of Corporation XYZ are part of XYZ's Zoom account). Put differently, you can use a JWT issued for the XYZ Zoom account to access information for all users under the XYZ Zoom account, but if you need data for users that are not part of the XYZ Zoom account, then you need an API Key and API Secret for their Zoom account(s) as well to generate JWTs that you can use to retrieve their data.
If you are building an integration/service that you want to make available to the general public, then you need to use OAuth:
This app can either be installed and managed across an account by
account admins (account-level app) or by users individually
(user-managed app).
This question already has answers here:
How to exclude an element from a Firestore query?
(8 answers)
Closed 1 year ago.
I am trying to retrieve UID of all the users except of the current user. I tried to do FirebaseAuth.getInstance().getUid(); but it returns CurrentUserUid. Is there a way for NOT getting UID of the current user?
When you are using your app, you are considered as a normal user and not an admin or privileged user. Client SDKs cannot fetch information about other users. You would have to use a secure environment such as Cloud Functions or your own along with Admin SDK to retrieve information about other users.
You can create a Callable Function that fetched a specific user by email or UID like this:
export const getUser = functions.https.onCall(async (data, context) => {
// Verify if the user requesting data is authorized
const {email} = data;
const userRecord = await admin.auth().getUserByEmail(email)
return userRecord.uid
});
You can then call this function from your Android app like this:
private Task<String> getUserInfo(String userEmail) {
// Create the arguments to the callable function.
Map<String, Object> data = new HashMap<>();
data.put("email", userEmail);
return mFunctions
.getHttpsCallable("getUser")
.call(data)
.continueWith(new Continuation<HttpsCallableResult, String>() {
#Override
public String then(#NonNull Task<HttpsCallableResult> task) throws Exception {
// This continuation runs on either success or failure, but if the task
// has failed then getResult() will throw an Exception which will be
// propagated down.
String result = (String) task.getResult().getData();
return result;
}
});
}
Do note that you must check if the user calling the function and requesting the data is authorized. You can check custom claims, the UID or any identifier that decides who can view others users' information.
If your application requires anyone to view all information, then you would have to use any database that stores users' information and can be fetched on your app because you cannot fetch that data using Client Auth SDK.
I'm working on an authentication plugin that uses JWT parsing to get details and update the user in Mesh.
I'd like to also create a new node and attach it to the User in Mesh, using the user.setNodeReference() // Is this how I associate a User to a node?
The problem is when I return the mapping result, if I create the user profile node, I see the mapToken() method invoked again with the same token as before, like it's looping. I've found this is due to the 'retry' capabilities in the router
If I dont attach a node to the user.nodeReference() then it proceeds as expected.
Thoughts?
#Override
public MappingResult mapToken(HttpServerRequest req, String uuid, JsonObject token) {
MappingResult result = new MappingResult();
if (uuid == null) {
log.info("First time login of the user");
} else {
log.info("Already synced user is logging in.");
}
log.info("Mapping user in plugin");
printToken(token);
String username = extractUsername(token).get();
UserUpdateRequest user = new UserUpdateRequest();
user.setUsername(username);
user.setEmailAddress(username);
user.setFirstname(token.getString("firstname", "firstname"));
user.setLastname(token.getString("lastname", "lastname"));
// TODO: Stop the infinite loop
if (uuid == null) {
log.info("Creating profile node");
user.setNodeReference(createProfileNode(username, token));
} else {
log.info("Updating profile node");
//updateProfileNode(uuid, token);
}
result.setUser(user);
...
}
private ExpandableNode createProfileNode(String username, JsonObject token) {
NodeCreateRequest nodeCreateRequest = new NodeCreateRequest()
.setLanguage("en")
.setSchemaName(getConfig().getProfileSchema())
.setParentNodeUuid(getConfig().getProfileParentUuid());
FieldMap fields = nodeCreateRequest.getFields();
fields.putString("name", username);
fillProfileFieldMappedValues(fields, token);
nodeCreateRequest.setFields(fields);
return this.adminClient.createNode(getConfig().getProjectName(), nodeCreateRequest).blockingGet();
}
Update
I checked the jti & iat - the token contains both.
I thought maybe if I subscribe to the USER_CREATED event, I could add a profile node after the user is created.
But I don't see this ever executed. I may be incorrectly subscribing to the local event bus.
getRxVertx().eventBus().localConsumer(MeshEvent.USER_CREATED.getAddress()).handler((message) -> {
try {
String uuid = JsonUtil.getMapper().readTree(message.body().toString()).get("uuid").asText();
adminClient().findUserByUuid(uuid).toSingle().doAfterSuccess(u -> {
u.setNodeReference(createProfileNode(u.getUuid()).getBody());
}).doOnError(e -> {
log.error("Failed to create user profile node: {}", e);
});
} catch (IOException e) {
log.error("Failed to deserialize user: {}", e);
}
});
Also, I don't need to set the user.setNodeReference() to reproduce the error, I only need to try creating a new node in the mapToken method. It will retry creating the user 10x then error out with an http 500.
I'll turn up logging to see if I can get more details.
Update
I've found that if I create the user first in the mapToken function, then create a node for the profile, I can add it to the user.setNodeReference() but I never see the node in the content browser [I create it at `{project}/profiles/{userProfileNode}], and I'm not able to see the node reference when I retrieve the user.
But the logs show the node was created successfully.
Does your token contain a token Id? (jti or iat). Mesh will use one of these values to determine whether the key mapping needs to be re-run for the token. The idea behind this is to avoid bogus mapping calls for tokens that have not changed. I suspect your token does not pass this check and will be passed always to the mapper plugin.
I might be able to give you more hints if I could see some logs.
I followed the guide on the Android docs but for some reason nothing is showing when i start my app.
I even tried logging the listeners but nothing is showing up in logcat.
I also changed the ad technology in admob setting to Custom set of ad technology providers, but still not working.
My code
ConsentInformation consentInformation = ConsentInformation.getInstance(getApplicationContext());
ConsentInformation.getInstance(getApplicationContext()).addTestDevice("6AE7D8950FE9E464D988F340C0D625B0");
ConsentInformation.getInstance(getApplicationContext()).
setDebugGeography(DebugGeography.DEBUG_GEOGRAPHY_EEA);
String[] publisherIds = {""};
consentInformation.requestConsentInfoUpdate(publisherIds, new ConsentInfoUpdateListener() {
#Override
public void onConsentInfoUpdated(ConsentStatus consentStatus) {
// User's consent status successfully updated.
Log.d(TAG,"onConsentInfoUpdated");
}
#Override
public void onFailedToUpdateConsentInfo(String errorDescription) {
// User's consent status failed to update.
Log.d(TAG,"onFailedToUpdateConsentInfo");
}
});
form = new ConsentForm.Builder(this, privacyUrl)
.withListener(new ConsentFormListener() {
#Override
public void onConsentFormLoaded() {
// Consent form loaded successfully.
Log.d(TAG,"form loaded!");
form.show();
}
#Override
public void onConsentFormOpened() {
// Consent form was displayed.
}
#Override
public void onConsentFormClosed(
ConsentStatus consentStatus, Boolean userPrefersAdFree) {
// Consent form was closed.
}
#Override
public void onConsentFormError(String errorDescription) {
// Consent form error.
Log.d(TAG,"form error!");
}
})
.withPersonalizedAdsOption()
.withNonPersonalizedAdsOption()
.withAdFreeOption()
.build();
form.load();
Gradle
dependencies {
classpath 'com.google.gms:google-services:4.3.2'
}
implementation 'com.google.android.ads.consent:consent-library:1.0.7'
implementation 'com.google.android.gms:play-services-plus:17.0.0'
implementation 'com.google.android.gms:play-services-ads:18.2.0'
EDIT
I tried it on a project which was pre android x and now it calls the listener onFailedToUpdateConsentInfo.
With following error message:
onFailedToUpdateConsentInfoCould not parse Event FE preflight response.
Searched a bit and found this could be because of an invalid pub id, but i'm certain i'm using the right one.
1) I think you forget to check isRequestLocationInEeaOrUnknown() method.
It will return true If user already agreed to the consent. In this case, you don't need to ask it again. I think you already agreed to consent.
wrap your code with
if(ConsentInformation.getInstance(context).isRequestLocationInEeaOrUnknown()){
//setup admob
}else{
//Ask for consent
}
2) You have to call form.show(); to present the form to the user, check Google Doc
I was still using test app id and test ad ids, remove them and change it with your id's and make sure you use it as a testdevice so you don't violate admob policies.
Like this
adLoader.loadAd(new AdRequest.Builder().addTestDevice(AdRequest.DEVICE_ID_EMULATOR).build());
So I know I can use email verification, or phone number verification, but what I want to do is a phone number verification after the user has registered or logged in. How do you connect this these two authentication methods. Finally, is there a function in Firebase to check if the user is verified by phone number or not? Thank you.
You can still use the APi provided by firebase to verify the number even if the user is authenticated. According to the docs , the authentication happens only when the user receives the confirmation code and generates a PhoneAuthCredential. If you just want to vrify the phone you can simply provide a custom reaction to the callback onVerificationCompleted.
Normally you set up the provider:
PhoneAuthProvider.getInstance().verifyPhoneNumber(
phoneNumber,
60,
TimeUnit.SECONDS,
this,
mCallbacks);
And you implement a series of callbacks.
mCallbacks = new PhoneAuthProvider.OnVerificationStateChangedCallbacks() {
#Override
public void onVerificationCompleted(PhoneAuthCredential credential) {
//No need to authenticate again, just react to verified number
//signInWithPhoneAuthCredential(credential);
}
#Override
public void onVerificationFailed(FirebaseException e) {
if (e instanceof FirebaseAuthInvalidCredentialsException) {
} else if (e instanceof FirebaseTooManyRequestsException) {
}
}
#Override
public void onCodeSent(String verificationId,
PhoneAuthProvider.ForceResendingToken token) {
mVerificationId = verificationId;
mResendToken = token;
}
};
According to your second question about to verify how the user is signed in you can check this answer to see how to check the firebase user authentication providers.
When a user is logged in you can get its phone number (if there is any) by calling:
FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();
String number = user.getPhoneNumber();