With Flutter, I am able to login with Facebook, and later I want to get the FacebookAccessToken because it is needed to correctly get the user photoURL.
Is there a way to get the token from FirebaseAuth? Or I must store this value in my code?
Login part, we have the access token:
FacebookLoginResult result = await new FacebookLogin().logIn(['email', 'public_profile']);
...
FacebookAccessToken accessToken = result.accessToken;
Now, let's say in another Widget, we want to get the user photoURL
final auth = FirebaseAuth.instance;
String url = auth.currentUser.photoURL;
This url must be appended with ?accessToken=<access_token> retrieved during the first step. There is a bug created. But for now, can we directly get it from FirebaseAuth?
The Facebook access token is available from the auth result immediately after the user signs in from the FacebookAuthCredential object as result.credential.accessToken. It is not available from the current user, so if you don't capture immediately after sign-in there's no way to find it later without going back to the Facebook SDK.
Also see:
Can I get a facebook access token from firebase.auth().currentUser?
How to get provider access token in Firebase functions?
Get Facebook/Google access token on Firebase Auth#onAuthStateChanged?
Related
I just made simple authentication app using aqueduct as a back end. I used codes from aqueduct documentation pages for login and registering. When I login with this code in backend
router
.route('/auth/token')
.link(() => AuthController(authServer));
I get back token, token type and expiration date, Is there any chance to also pass userId? Or do I have to create my own controller to do that?
UPDATE
or how can I in my backend to save user id when saving the data
#Operation.post()
Future<Response> addData(#Bind.body(ignore: ['id']) Data newData) async {
final query = Query<Data>(context)..values = newData;
final insertData = await query.insert();
return Response.ok(insertData);
}
Flutter frontend
Login initially with the username/email and password. You will get an authorization token back from the server if the username and password are valid. Then use that token to make further privileged requests to the server.
You don't need to save any personal data about the user (email or password) on the client. You can save the token, though, if you don't want to make the user log in again the next time they use the app. When saving the token you should use a secure storage option. The flutter_secure_storage plugin uses KeyChain on iOS and KeyStore on Android.
Aqueduct backend
You can use the user IDs all you want on the backend. I don't know of any need to pass them to the client, though. On the backend you can query the user ID and then use it to fetch other information from the database.
Here is an example from the documentation:
class NewsFeedController extends ResourceController {
NewsFeedController(this.context);
ManagedContext context;
#Operation.get()
Future<Response> getNewsFeed() async {
var forUserID = request.authorization.ownerID;
var query = Query<Post>(context)
..where((p) => p.author).identifiedBy(forUserID);
return Response.ok(await query.fetch());
}
}
The client only passed in the token. Aqueduct looks up the user id for you based on that token. Now you know the user ID.
Your other tables can have a column for the user ID so that only that user may save and retrieve their data. In the example above, Posts have an Author and an Author has an ID, that is, the user ID.
where((p) => p.author).identifiedBy(forUserID)
is equivalent to
where((p) => p.author.id).equalTo(forUserID)
You can read about this in the Advanced Queries section of the documentation.
I am developing an app that verify the custom claims for a user using the following code:
firebase.auth().currentUser.getIdToken().then(idToken => {
// Parse the ID token.
const payload = JSON.parse(window.atob(idToken.split(".")[1]));
// Confirm the user is an Admin.
if (!!payload["admin"]) { // continue
But I realised that some users that logged in using Facebook receives the error below:
DOMException: Failed to execute 'atob' on 'Window': The string to be decoded is not correctly encoded.
These users don't have any custom claim attributed in the app. It looks like that some Facebook's users already receives an idToken from login that is not compatible with atob function. It's not happen to all Facebook users.
Would someone know why some users is receiving an idToken when log in Firebase UI through Facebook ?
In my DialogFlow V1 Webhook, I used to get the user's access token like this (node.js):
exports.voxGoogleHomeWebhook = functions.https.onRequest((req, res) => {
const app = new WebhookClient({request: req, response: res});
var accessToken = app.getUser().accessToken
This does not work in DialogFlow V2. getUser() is not available on instance of WebhookClient.
I can not find in their documentation, how to get the accessToken of the Logged In user:
https://dialogflow.com/docs/fulfillment
I tried getting app.session, but that's just the unique session string Identifier of the user's session. It's not their access token.
How can I get the accessToken in V2?
It looks like the portion of the request object that contains this info isn't (yet) handled by the library. I've opened a bug on the issue, and you may wish to follow or comment on it.
In the meantime, you can access the user information by looking at the req.body object. Specifically you can look at req.body.originalDetectIntentRequest.payload.user to get the User object. The accessToken field there is the one you're looking for.
I have an app with an Uber login that gives access to restricted API calls (info on the current ride). I'd like to share the login token with the associated Today Widget so it can make similar calls.
I'm already sharing data with a UserDefaults suite, and I'm using the UberRides SDK. In digging into the RidesClient object it seems to try to use the keychain for storing/sharing the login token, and I set up a shared keychain to try to take advantage of this, but no luck. Restricted API calls from the widget return as unauthorized. Any suggestions?
Here's some code from the widget (note the user already authenticated in the main app):
let rc = RidesClient()
rc.fetchCurrentRide { ride, response in
if ride == nil { print("NO CURRENT RIDE") }
print(response.response)
print(response.error?.title)
if let ride = ride {
// do something
} else {
self.ride = nil
}
}
This returns an unauthorized response. I traced into the RidesClient (which is an object in the UberRides SDK), and see the code where the token is "supposed" to come from the keychain, but it doesn't.
I also tried generating my own URL request in the widget, using the login token passed through shared UserDefaults. This followed the standard HTTP access approach, putting the token in the Authorization header. But I got the same unauthorized response.
Here's some more details on the SDK approach:
Main app uses the LoginButton in native mode:
let scopes: [RidesScope] = [.Profile, .Places, .Request, .AllTrips]
let loginManager = LoginManager(accessTokenIdentifier: Configuration.getDefaultAccessTokenIdentifier(), keychainAccessGroup: "com.MYCOMPANY.MYAPP.share", loginType: .native)
let loginButton = LoginButton(frame: loginFrame, scopes: scopes, loginManager: loginManager)
loginButton.presentingViewController = self
loginButton.delegate = self
view.addSubview(loginButton)
The login button does the right thing and authorizes in the Uber app. I can see the token returned in the delegate callback didCompleteLoginWithToken. However, I can then check for the token:
let token = TokenManager.fetchToken(Configuration.getDefaultAccessTokenIdentifier(), accessGroup: "com.MYCOMPANY.MYAPP.share")
print(token)
The token is "nil". I don't think the SDK is saving the token into the access group keychain.
When I use the default keychain (not the keychainAccessGroup), the login in the app works fine and I can get the login token back and make restricted calls to the API. However, that doesn't help the widget, which needs the token from the access group keychain.
Solved!! After many hours of debugging, and searching. What was not clear in ANY documentation is the keychainAccessGroup MUST include the AppIndentifierPrefix. That's the 10 character identifier associated with the App ID. So, instead of using "com.MYCOMPANY.MYAPP.share", it's "APPID.com.MYCOMPANY.MYAPP.share" for the keychainAccessGroup.
the facebook canvas app gets a "signed_request" parameter when user visits the canvas url via facebook.
How do i use this to authenticate the user on servicestack, so that i get the user session in servicestack.
the user will already be signed up for the app and will have records in the servicestack user repositories.
Should i set the canvas url to /auth/facebook ? with additional ?Continue=/target_url
Will this authenticate the user and send him to the target_url?
Or should i handle the canvas request and then use AuthService to authenticate the user using the "signed_request" param? if this is the case then, how do i proceed with it ?
Here's how I managed the case:
I handled the FB canvas request, receiving the "signed_request" parameter. Then by decoding the BASE64 encoded string (and verifying with HMAC SHA256), I got the FB userId.
if (isMatch)
{
string message = UTF8Encoding.UTF8.GetString(msg);
var output = message.FromJson<Dictionary<string, string>>();
string user = output["user_id"];
OAuthTokens tokens = new OAuthTokens();
tokens.Provider = "facebook";
tokens.UserId = user;
UserSession.IsAuthenticated = true;
((FacebookAuthProvider)AuthService.GetAuthProvider("facebook")).OnAuthenticated(this, UserSession, tokens, new Dictionary<string, string>());
return UserSession.ToJson();
}
I'm not sure whether this is the best way to manually get the user authenticated. But so far, this technique has worked.