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'))})()");
}
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'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()
As the title says, I'm trying to use the Google Sign-In API with a Spring Boot backend server, as described here.
Just to describe the context, the Spring backend is basically a resource+authentication server, that is currently providing Oauth2 authentication to a second spring boot application containing the frontend website, via Google SSO or simple form login (similar to what's described here).
My original idea was to mimic the #EnableOauth2Sso annotation by simply providing an access token to the android app and attach it to every request as "Bearer ".
Using the user credentials for this was pretty straightforward: I simply make a request to the server at "/oauth/token", using those credentials inserted by the user as authentication and I correctly receive the access token.
Now, I have absolutely no idea on how to build a similar procedure with the Google API in Android. The tutorial page I linked before describes how to get a token ID and how the server should validate it, but after that I don't know what to do.
So far I've managed to add a filter to the security chain that simply checks the token like this:
private Authentication attemptOpenIDAuthentication(#NonNull String tokenString){
String clientId = authServices.getClientId();
GoogleIdTokenVerifier verifier = new GoogleIdTokenVerifier.Builder(transport, factory)
.setAudience(Arrays.asList(clientId, androidClient))
.build();
try {
GoogleIdToken token = verifier.verify(tokenString);
if (token != null) {
return authServices.loadAuthentication(token.getPayload());
} else {
throw new InvalidTokenException("ID token is null");
}
} catch (GeneralSecurityException | IOException e) {
throw new BadCredentialsException("Could not validate ID token");
}
}
This manages indeed to create an Authentication object, but how can I generate an access token after the authentication filtering?
To recap, so far I've got:
The Android app successfully retrieves the Google token ID and sends it to the server
The server sucessfully intercepts the request and validates the token
I'm basically missing the third point where I return a proper access token to the Android client.
Here you are a simple scheme to better understand the situation:
Is there any other way to validate the token and get an access token from the server, or should I completely change the authentication procedure on Android?
As far as I can tell: Yes, you need an access token from the server. If I understand this correctly, a webapp is already authenticated via Oauth on your backend, so the procedure is similar here: Load the user with the google-ID and generate a token. In my application I used a JWT which is valid for 30 days. If the token expires, the Google authentication in the app is usually still valid, so the token can be renewed using the Google ID. With Oauth you can also send a refresh-token directly.
It is important that the app always checks the Google authentication first and only in a second step that of the backend.
For the Authentication process on the backend u may need to manually implement a dedicated securityConfiguration for this. Have a look at the jhipster project, they implemented a custom jwt-authentication which may give you an idea how it works.
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 :(.