I perform API call with Retrofit2 to login user via Firebase Authentication with email and password and after that need to interact somehow with user object, i.e. refresh some data or check if user logged in on next time application starts (I'm getting a correct Json object).
But after API call checking FirebaseAuth object mAuth.getCurrentUser() gives null and have no idea how to save login state inside my app.
NetworkService.getInstance().getJsonApi()
.loginWithEmail(email, password, true)
.enqueue(new Callback<Transaction.Result>() {
#Override
public void onResponse(Call<Transaction.Result> call, Response<Transaction.Result> response) {
if (response.code() == 200) {
// Sign in success, update UI with the signed-in user's information
Log.d(TAG, "signInWithEmail:success");
FirebaseUser user = mAuth.getCurrentUser();
activity.updateUI(user);
activity.startService();
} else {
Log.d(TAG, "signInWithEmail:failure");
activity.showToast("Authentication failed.");
activity.updateUI(null);
}
activity.hideProgressBar();
}
#Override
public void onFailure(Call<Transaction.Result> call, Throwable t) {
t.printStackTrace();
}
});
How to retrieve FirebaseUser correctly?
Thanks.
If you're using the Firebase Auth REST API to sign in a user, you can't also use the Firebase Auth SDK to manage that sign-in. You will have to stick to using the REST API for all management. This means that you'll have to track the ID token that you get from the API, refresh the token every hour before it expires, and maintain your own sense of what it means for the user to be "signed in".
I highly suggest just using the provided SDK, as it will do all of this for you automatically.
Related
I added Facebook login button to my code. it works well.
Assuming that the user logs in via facebook and unchecks the 'user_friends' permission: 'onSuccess' function will be called so the user data can be taken from the loginResult.
Next time when he opens the app, he will get the facebook permission screen in order to allow the 'user_friends' permission. Let's say that he unchecks it again: 'onCancel' function will be called although the user will be now logged in automatically as expected (because he has never logged out).
How can I get his data now in onCancel? (because I know that he is logged in but unchecked some permission)
The User logged in last time and not this time so onSuccess won't be called this time
mCallbackManager = CallbackManager.Factory.create();
mLoginButtonFacebook.registerCallback(mCallbackManager, new FacebookCallback<LoginResult>() {
#Override
public void onSuccess(LoginResult loginResult) {
}
#Override
public void onCancel() {
AccessToken token = AccessToken.getCurrentAccessToken();
if (token != null) {
// here I would like to retrieve the user data
// the user is logged in with canceled permissions
}
}
#Override
public void onError(FacebookException exception) {
}
});
Succeeded! sorry for your time and thanks.
AccessToken accessToken = AccessToken.getCurrentAccessToken();
GraphRequest request = GraphRequest.newMeRequest(accessToken, new GraphRequest.GraphJSONObjectCallback() {
#Override
public void onCompleted(JSONObject object, GraphResponse response) {
// object will contain the user data
}
});
I am trying to get Auth0 integrated into my web app which uses the spark-java framework.
The problem is while the authentication works perfectly, including the callback(I see the new user created on Auth0's website and my website gets redirected), I can't access the logged in user info. I've tried several methods like SessionUtils.getAuth0User(request.raw()) and none of them are working.
For example in the provided tutorial here: https://github.com/auth0-samples/auth0-servlet-sample/tree/master/01-Login
they access the logged in user info like so:
#Override
protected void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
final Auth0User user = SessionUtils.getAuth0User(req);
if (user != null) {
req.setAttribute("user", user);
}
req.getRequestDispatcher("/WEB-INF/jsp/home.jsp").forward(req, res);
}
I've tried doing something similar with Spark but since the get works a bit differently in Spark I do this:
port(Integer.valueOf(System.getenv("PORT")));
staticFileLocation("/spark/template/freemarker");
String clientId = System.getenv("AUTH0_CLIENT_ID");
String clientDomain = System.getenv("AUTH0_DOMAIN");
get("/", (request, response) ->
{
Map<String, Object> attributes = new HashMap<>();
Auth0User user = SessionUtils.getAuth0User(request.raw());
if(user != null) {
attributes.put("user", user);
attributes.put("loggedIn" , true);
}
else
attributes.put("loggedIn" , false);
attributes.put("clientId" , clientId);
attributes.put("clientDomain" , clientDomain);
return new ModelAndView(attributes, "index.ftl");
}, new FreeMarkerEngine());
The code is always reporting the user as null even though the user is created and stored in the database and the signin works properly with no runtime or console errors. The other methods I tried I replaced the line where I set the user variable and wrote the following.
Alternate Method 1:
Auth0User user = (Auth0User) request.session().attribute("auth0User");
Here auth0User is the same string literal Auth0 uses in their implementation of SessionUtils as shown in their source code referenced here: https://github.com/auth0/auth0-java-mvc-common/blob/master/src/main/java/com/auth0/SessionUtils.java
Alternate Method 2:
Auth0User user = (Auth0User) request.raw().getUserPrincipal();
In addition this is my javascript code running client side for the authentication:
var lock = new Auth0Lock('${clientId}', '${clientDomain}', {
auth: {
redirectUrl: 'http://localhost:5000/build',
responseType: 'code',
params: {
scope: 'openid user_id name nickname email picture'
}
}
});
$(document).ready(function()
{
$('.signup').click(function()
{
doSignup();
});
});
function doSignup() {
lock.show();
}
I have no idea why user is being evaluated to null every time and I would love some feedback on what I'm doing wrong. Thanks.
In order for you to get a non null user instance from SessionUtils.getAuth0User(req) some piece of code must first call SessionUtils.setAuth0User. This should be done when you receive confirmation that the user authenticated with success.
In the auth0-servlet-sample you were using as reference this is done by configuring an Auth0ServletCallback that will handle requests performed to /callback endpoint. Since the Auth0ServletCallback calls (see code below) the set user for you, in the servlet example you can then get the user with success.
protected void store(final Tokens tokens, final Auth0User user, final HttpServletRequest req)
{
SessionUtils.setTokens(req, tokens);
SessionUtils.setAuth0User(req, user);
}
At the moment the available samples (auth0-servlet-sample, auth0-servlet-sso-sample, auth0-spring-mvc-sample, auth0-spring-security-api-sample and auth0-spring-security-mvc-sample) don't include one for spark-java so I can't refer you to any sample.
In order to solve this you have to include additional logic to process the result of the authentication operation in your spark-java application and in case of success call the SessionUtils.setAuth0User yourself if you then want to use the corresponding SessionUtils.getAuth0User method.
For general guidance on integrating a web application with Auth0 check Integrating a Web App with Auth0.
I am trying to setup login on my app using facebook. Currently I have the SDK working fine, it authenticates and I can accession user information and then I start an Intent to my activity. (not sure if this is what I should be doing)
Now I am wondering what the workflow is for this is to authenticate with my RestAPI.
I can post the facebook_id to my server and add to my users database but I then read that I should be using the AccessToken, but how do I know if this is the correct AccessToken for that user?
What should be the flow here? Where should I be posting to the server and what should I be posting for every request in every Activity?
Here is my code I currently have.
private Session.StatusCallback statusCallback = new Session.StatusCallback() {
#Override
public void call(final Session session, SessionState sessionState, Exception e) {
if (sessionState.isOpened()) {
Request.newMeRequest(session, new Request.GraphUserCallback() {
#Override
public void onCompleted(GraphUser graphUser, Response response) {
if (graphUser != null) {
Log.w(TAG, graphUser.getFirstName() + ' ' + graphUser.getId());
Log.w(TAG, session.getAccessToken() + ' ' + session.getExpirationDate());
Intent intent = new Intent(LoginActivityFragment.this, MainActivity.class);
startActivity(intent);
}
}
}).executeAsync();
} else if (sessionState.isClosed()) {
}
}
};
You should use the user ID as the unique identifier. The access token can change under many situations (updated permissions, user log in/out, etc), and should not be used to identify someone. The user ID will remain stable within your app.
You can send the access token along with the ID to your server, perhaps to make some FB requests from the server side, but that's a separate issue.
I have been battling this problem for hours now and I seem to get nowhere with it. So, I have successfully asked the users to login using Facebook to my android app.
Once they are logged in, I get the access token (a string value) and then use it to make a Request to Facebook to fetch a Page's Posts. Here is how I do that whole process.
public void setupFacebook()
{
Session.openActiveSession(this, true, new Session.StatusCallback()
{
// callback when session changes state
#Override
public void call(Session mSession, SessionState state, Exception exception) {
if (mSession.isOpened() && mSession != null)
{
facebookAccessToken = mSession.getAccessToken();
Log.d("ACCESSTOKEN", facebookAccessToken);
fetchPagePosts(facebookAccessToken, mSession);
}
}
});
}
public void fetchPagePosts(String token, Session session)
{
Request.Callback callback = new Request.Callback()
{
#Override
public void onCompleted(Response response)
{
Log.d("RESPONSE", "ERROR"+response.getError());
Log.d("RESPONSE", ""+response);
}
};
String endpoint = String.format("https://graph.facebook.com/"+pageId+"/posts?access_token=%s", facebookAccessToken);
Log.d("ENDPOINT", endpoint);
Request request = new Request(session, endpoint, null, HttpMethod.GET, callback);
RequestAsyncTask task = new RequestAsyncTask(request);
task.execute();
}
The interesting part here is that when I copy the url from my Logcat (what I called endpoint) and paste to my browser, it works perfectly fine.
When I run my code on my tablet though, it returns the ErrorCode 190 and HttpStatus 400.
According to Facebook's documentation, it could be one of several things;
Access token is invalid
It is expired
The user has changed their password or
The user has logged out of their account
The user has revoked access to their account by your app!
I am stuck here because I have tested the same URL on the browser and it returns the json data I need. It just fails when am running it in android code.
If anyone has suggestions, please help me - will be truly thankful for your help.
Thank you in advance.
You could try using the Simple Facebook Android library instead of the Facebook SDK https://github.com/sromku/android-simple-facebook, its a lot simpler.
I've been using Google OAuth to let users authorize access to the Calendar Service for my Web Application. After a successful 3-legged auth flow, I was storing all user's credentials in a common file on the app Server. The next time the app needs to use the service, it will check if the credentials exist, and if yes, it will assume they are valid
code works like that
#Override
public void _authorize(String userId) throws IOException {
// Check if user has already authorised the service.
Credential credents = flow.loadCredential(userId);
// Checking if the given user is not authorized
if (credents == null) {
//Create credentials now. user will be redirected to authorise
try {
//Creating a LocalServer Receiver
// Getting the redirect URI
// Creating a new authorization URL
// Setting the redirect URI
// Building the authorization URL
// Receiving authorization code
// Exchanging it for an access token
// Storing the credentials for later access
credents = flow.createAndStoreCredential(response, id);
} finally {
// Releasing resources
}
} else {
// Assume the credentials are valid. so there's nothing left to do here, let's get that client
//Update: Nooooooot! the user might have revoked the authorization, so credents != null BUT they are invalid
//TODO: handle an Exception here, and manage the revoked credentials
}
// Setting up the calendar service client
client = new com.google.api.services.calendar.Calendar.Builder(httpTransport, jsonFactory, credents).setApplicationName(APPLICATION_NAME)
.build();
}
This works fine, as long as the user never changes his mind. But if the user decides to manually revoke the authorization using the Google Account security options, the com.google.api.services.calendar.Calendar retrieval will Fail.
My question is :
Is there a way to check if the credentials are still valid, before trying to use them ?
Else, I can only guess that the failure to get the client object, is the only way to have my portal realize that the credentials are no more valid ?
What should I do about the invalid/revoked credentials ? should I just call flow.createAndStoreCredential and they are going to be overwritten? Or do I have to delete the old ones first ? (how ?)
You can use the refreshToken() method for this. See example:
// Fetch credential using the GoogleAuthorizationCodeFlow
GoogleAuthorizationCodeFlow authorizationCodeFlow;
Credential credential = authorizationCodeFlow.loadCredential(userId);
if (credential != null) {
try {
// refresh the credential to see if the refresh token is still valid
credential.refreshToken();
System.out.println("Refreshed: expires in: " + credential.getExpiresInSeconds());
} catch (TokenResponseException e) {
// process exception here.
// This will catch the Exception.
// This Exception contains the HTTP status and reason etc.
// In case of a revoke, this will throw something like a 401 - "invalid_grant"
return;
}
} else {
// No credential yet known.
// Flow for creating a new credential here
}
EDIT
If you indeed have an invalid refresh token and you want to renew it, then you need to repeat the steps that you did in the first place to get the credentials. So:
genererate a new authorization URL
redirect the user to it
user accepts the consent screen
catch the authorization code from the redirect back to your app
request a new token from Google using the authorization code
create and store a new Credential using the response from Google
No need to delete the old credential. But if you want to explicitly do so, it is possible.
Something like:
// This userId is obviously the same as you used to create the credential
String userId = "john.doe";
authorizationCodeFlow.getDataStore().delete(userId);
You can use the endpoint https://www.googleapis.com/oauth2/v1/tokeninfo to determine if an OAuth2 token is still valid. More information is available in the OAuth2 guide.
Answer to the first question:
When using the Service object for retrieving calendar items from Google Calendar, the token are automatically verified. When they are invalid, they will be refreshed automatically, and stored in the datastore you provided to the flow.
this can also be done manually. A token is valid for 3600 seconds (one hour). When retrieving a token you get this value with the timestamp when it was issued. You could manually determine if a token is valid. If it is not valid call the following async method.
await credents.RefreshtokenAsync(CancellationToken.None);
This function gets you fresh tokens, and stores them in the datastore you provided.
You could check token with tokeninfo and if token is not valid:
- remove credential from datastore
- invoke new auth
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
{
UserService userService = UserServiceFactory.getUserService();
if (userService.isUserLoggedIn()) {
User user = userService.getCurrentUser();
log.info(String.format("LoggedUser: %s %s", user.getEmail(), user.getUserId()));
Credential credential = this.getCredential();
Tokeninfo tokenInfo = OAuth2Utils.getTokenInfo(credential, null);
if (tokenInfo != null)
log.info(String.format("Token expires in: %d", tokenInfo.getExpiresIn()));
else {
OAuth2Utils.deleteCredential(user.getUserId());
response.sendRedirect(request.getRequestURI()); // recall this servlet to require new user authorization
return;
}
}
public static Tokeninfo getTokenInfo(Credential credential, String accessToken) {
Oauth2 service = new Oauth2.Builder(new NetHttpTransport(), Constant.JSON_FACTORY, credential).setApplicationName(Constant.APP_NAME).build();
Tokeninfo tokenInfo = null;
try {
tokenInfo = service.tokeninfo().setAccessToken( accessToken == null ? credential.getAccessToken() : accessToken ).execute();
} catch (IOException e) {
log.warning("An error occurred: " + e);
}
return tokenInfo;
}