I'm making an Android app that will be using a REST API that I'm building in Firebase Functions and I have a question regarding user authentication.
As far as I've gathered, I have to send the user's idToken to the API with every HTTP call, to verify that the user is logged in and can access the API resource. So far so good.
I'm following this guide for sending the idToken:
https://firebase.google.com/docs/auth/admin/verify-id-tokens
What confuses me is that with that piece of code, it seems that I have to build all my code within the "if (task.isSuccessful())" part to be able to use the idToken, since I can't return any values from that inner class, to be used elsewhere in the app.
Isn't that impractical, since it would mean that I have to fetch the idToken every time I want to make an HTTP call, instead of reusing the one I've already found?
I considered storing the idToken in a cookie, but it seems that cookie would still be "locked" to the inner class, isn't that right?
How do (normal) people normally do this?
FirebaseUser mUser = FirebaseAuth.getInstance().getCurrentUser();
mUser.getIdToken(true)
.addOnCompleteListener(new OnCompleteListener<GetTokenResult>() {
public void onComplete(#NonNull Task<GetTokenResult> task) {
if (task.isSuccessful()) {
String idToken = task.getResult().getToken();
// Send token to your backend via HTTPS
// ...
} else {
// Handle error -> task.getException();
}
}
});
there are two ways to call firebase functions from android app
1;) as a rest api
2:) using firebase functions library to call it directly (easier)
currently you are trying to use first option . drawbacks of this way is that you need to send id token with each request and verify it in cloud functions .
if you use 2nd way then you won't have to send idtoken yourself and firebase library will take care of that
check this link to know how to make direct function calls
https://firebase.google.com/docs/functions/callable
but if you want to keep using first way then you need to save the idtoken in local storage like this
public static void setAccessToken(Context context,String val){
PreferenceManager.getDefaultSharedPreferences(context).edit().putString("idToken",val).apply();
}
public static String getAccessToken(Context context){
return PreferenceManager.getDefaultSharedPreferences(context).getString("idToken",null);
}
call setAccessToken() within callback once when you login and when you need to call a function you can get the previous stored token with getAccessToken()
Related
I have integrated the docuSign Android SDK in my app and been able to achieve embedded signing. But it asks for the customer to login before signing the document. As its a customer facing app, we dont want them to enter the organisation docusign credentials.
How can we skip the login or authenticate implicitly using the SDK methods or some other way?
Thanks in Advance!!
In Android SDK, we provide the following apis to login or authenticate.
Login with Access Token:
You can invoke the following SDK API:
// accessToken - Access Token which authenticates the user
// refreshToken - If the access token can be refreshed, the refresh token. Optional
// expiresIn - The number of seconds from the time the access token was provisioned to when it will expire
try {
DSAuthenticationDelegate docusignAuthDelegate = DocuSign.getInstance().getAuthenticationDelegate();
docusignAuthDelegate.login(accessToken, refreshToken, expiresIn, context,
new DSAuthenticationListener() {
#Override
public void onSuccess(#NonNull DSUser user) {
// TODO: handle successful authentication here
}
#Override
public void onError(#NonNull DSAuthenticationException exception) {
// TODO: handle authentication failure here
}
}
);
} catch (DocuSignNotInitializedException exception) {
// TODO: handle error. This means the SDK object was not properly initialized
}
You can retrieve access token the following ways:
a. Using JWT Grant authentication by following steps mentioned at https://developers.docusign.com/platform/auth/jwt/jwt-get-token/
b. Using Authorization Code Grant by following the steps mentioned at https://developers.docusign.com/platform/auth/authcode/authcode-get-token/
Using JWT Grant authentication to fetch access token needs to be implemented at your backend and once your server receives access token from DocuSign using this approach, then your server needs to pass that access token and the expiration time to your app and your app can invoke the above mentioned Android SDK login api with access token and expiration time.
Login using OAuth:
UI is displayed where user enters credentials.
Get the OAuth Client Id/Integration key, secret key and redirectUri from your account. (Please refer to https://developers.docusign.com/platform/auth/authcode/authcode-get-token/ on how to retrieve the clientId, secretKey and redirectUri from your account).
While initializing the DocuSign SDk, pass these values as shown in below
DocuSign.init(
context,
clientId,
secretKey,
redirectUri,
DSMode.DEBUG
).setEnvironment(environment)
DSAuthenticationDelegate authenticationDelegate = DocuSign.getInstance().getAuthenticationDelegate();
authenticationDelegate.login(REQUEST_LOGIN, this, new DSAuthenticationListener() {
}
This will open the OAuth login screen. Enter your username and password and you should be able to login.
In your use case, you can use SDK 'Login with Access Token' approach.
i am currently using a custom webview on my Xamarin Forms App. I need to communicate with an api that needs an access token to return values. So far so good, I am able to login, receive my login data including my first access and refresh token via callback and store it on the smartphone in a sqlite database.
But how can I notice if the access token changes?
Since I have only stored the access Token on login, how can I react if the session of the webview updates the access token with the refresh token?
I need the new token for my native api calls, without a new login, since the webview refreshes the access token I somehow want to receive the current access token from my webview local storage.
Is there any way to grab the current access token from the webview local storage?
Generally, when we use the outdated token request API, the background server will verify the token requested. If the token expires, it will return the corresponding feedback data, and then the APP will pop up the user with such tips as: Token expired, please login again..
Then the APP will jump to the login page and login again to get the latest token.
Update 1:
Well, since Token can only be obtained at login time, so when you request a API and find the token has expired, you can login again and abtain the latest token.
But we don't recommend this ,because it defeats one of the purpose of token:Using for authentication.
For example, if a user logs in and doesn't use it for a long time, and another person with ulterior motives get the phone and use the APP, he can successfully use the APP and get some private information, even if the token expires.
Update 2:
Yes, it is possible to get the userKey field stored in LocalStorage.
For example, if you want to get the userKey field stored in LocalStorage, you can do like this:
1.Write an interface to accept Js callbacks
public class MyJSInterface : Java.Lang.Object, Java.Lang.IRunnable
{
Context context;
public MyJSInterface(Context context)
{
this.context = context;
}
[JavascriptInterface]
[Export]
public void Run()
{
Toast.MakeText(context, "Hello from C#", ToastLength.Short).Show();
}
}
2.Add to WebView and rename to "shixintest" :
mWebView.AddJavascriptInterface(new MyJSInterface(this), "shixintest");
3.call JS
private void getLocalStorageUserKey()
{
if (mWebView != null && TextUtils.IsEmpty(APPEnvironment.GetBeforeLoginUserKey()))
{
mWebView.LoadUrl(
"javascript:(function(){
var localStorage = window.localStorage; window.shixintest.getUserKey(localStorage.getItem('userKey'))})()");
}
My applicaion needs to work in secure environment and it can connect
only with speficic server. In other words, traffic that goes outside our app
is restricted. Because of that I have some doubts about Firebase notifications
functionality in this application.
I need to get Firebase token in order to send it to our server.
Ofcourse Firebase's server needs to identify client device in some way. I assume
that before receiving new token, some part needs to send data (like device id) to Firebase server in order
to generate that token that will be send back to me. So, the questions is... Who is responsible
for initializing this process? Under the hood, does the system do the work or my application?
For get token from firebase, you just need to do :
FirebaseInstanceId.getInstance().getInstanceId()
.addOnCompleteListener(new OnCompleteListener<InstanceIdResult>() {
#Override
public void onComplete(#NonNull Task<InstanceIdResult> task) {
if (!task.isSuccessful()) {
Log.w("token", "getInstanceId failed", task.getException());
return;
}
// Get new Instance ID token
token = task.getResult().getToken();
Log.w("token", token);
}
});
You don't need to send anything.
For example, in my app I execute this code in SplashScreen, in this case the token can be directly send with the user login request.
I'm developing an Android app which is using Oauth2 tokens to get authorization in order to access secured resources. I'm using a third party platform as the authentication server (using OpenId Connect). Basically my problem is that I want to deal with an expired refresh token.
Current scenario
I've got a NetUtils class which acts like a singleton and manages all my requests using a secured rest template. That rest template injects the required Authorization header for each request using a request wrapper. The NetUtils class deals whith tokens and timeouts, saving them in user preferences and refreshing them when it's needed.
However, the problem comes when the refresh token itself expires. As I'm using the Authorization code flow, I need to open a WebView and redirect the user to the login page, but I notice it when the NetUtils class determinates the refresh token has expired. Ideally, the app would launch a WebView, the user would login again and the stored request would be executed. Here it is my code to refresh the access token:
private AccessToken refreshToken(String idClient, String clientSecret, AccessToken accessToken) {
MultiValueMap<String, String> clientAuthenticationForm = new LinkedMultiValueMap<>();
clientAuthenticationForm.add("grant_type", "refresh_token");
clientAuthenticationForm.add("refresh_token", accessToken.getRefreshToken());
clientAuthenticationForm.add("client_id", idClient);
clientAuthenticationForm.add("client_secret", clientSecret);
try {
long lastClientRefresh = mPrefs.getLong(Preferences.LAST_LOGIN_TIME, Long.MIN_VALUE);
boolean refreshTokenExpired = lastClientRefresh
+ TimeUnit.SECONDS.toMillis(accessToken.getRefreshExpiresIn()) < System
.currentTimeMillis();
if (!refreshTokenExpired) {
return regularRestTemplate
.postForEntity(tokenUrl(), clientAuthenticationForm, AccessToken.class)
.getBody();
}else{
//How to cope with this?
return null;
}
} catch (Exception ex) {
Log.e(TAG, ex.getMessage(), ex);
throw ex;
}
}
Other choice
Other choice would be to make the refresh token long lived and refresh it each time the app starts, for example. I have to mention that client_id and client_secret are currently being hardcoded in the app (although client credential grants are not meant to be enabled in production, so there's still the need to provide a username and password to retrieve a token).
What would be the best practice here?
I think I can't suggest you how to code in Java, but I also had some troubles with refresh_token while creating application in PHP so maybe my thoughts will help you with something.
At first I was looking for refresh_token which never expires (like in Google API) so I can even hardcode it and use whenever I want to create a new access_token. Anyway it's really hard to do in oAuth2. So I have found a interesting look on this problem here:
Why do access tokens expire?
It showed me a bit other way to work with refresh_token. I have set on my oAuth service that it generates and returns a new refresh_token everytime I use refresh_token to obtain a new access_token. That part helped me most:
https://bshaffer.github.io/oauth2-server-php-docs/grant-types/refresh-token/
And there we got something like:
$server = new OAuth2\Server($storage, array(
'always_issue_new_refresh_token' => true, // this part
'refresh_token_lifetime' => 2419200,
));
In this case I have a long live refresh_token which I can store somewhere and when I need it I will use it to get a new access_token, but response will also provide me a new refresh_token which I can store again and use it later for obtaining a new access_token.
So in your case I think the best way is to keep generating refresh_token everytime you ask for access_token with refresh_token. And if user will not use your APP for longer time, I think he should authorize himself again.
In the example OutlookQuickStart for Android works fine in the first request after logon().Now I want to keep connect my app to that user and continue checking for new emails.. How can I re use the access token and build the request to check for new emails? Do I have to save the access token, refresh token ?
How I can refresh the token in Android if it is expired.
According to the documentation for the auth library at https://github.com/AzureAD/azure-activedirectory-library-for-android, the library caches the token and refresh token for you. So you would just use acquireTokenSilentSync to get the token each time you need it. That function would return the current token from the cache if it is still valid, and would refresh it if it is expired.
UPDATE: I've taken a closer look at the sample you're using and the Outlook SDK that it uses. The key thing here is the DependencyResolver object. You pass that object to the OutlookClient constructor. Then anytime you make an API call with that OutlookClient, it just calls the getCredentials override that you supply when you create the DependencyResolver.
So as the sample stands, you should be able to make multiple calls through that OutlookClient without having to change it at all. However, after an hour, when the access token expires, calls will start to fail. The fix for that would be to change the getCredentials override to always call acquireTokenSilentSync. Something like:
#Override
public Credentials getCredentials() {
logger.debug("getCredentials in resolver called");
AuthenticationResult result = mAuthContext.acquireTokenSilentSync(
scopes,
getResources().getString(R.string.AADClientId),
UserIdentifier.getAnyUser());
logger.debug("AcquireTokenSilentSync SUCCESS");
logger.debug("Token expires: ", result.getExpiresOn());
logger.debug("Token: ", result.getAccessToken());
return new OAuthCredentials(result.getAccessToken());
}
Caveat: I'm unable to run this code to validate it due to problems getting the Android emulator running on my dev machine :(.