From 4555477440802e336e035eda7aebf856685d66d2 Mon Sep 17 00:00:00 2001 From: Carmen Date: Thu, 6 Aug 2026 21:10:39 +0100 Subject: [PATCH 1/5] Add example app button to refresh access token directly --- .../com/oursky/authgeartest/MainActivity.java | 14 ++++++++++ .../oursky/authgeartest/MainViewModel.java | 26 +++++++++++++++++++ .../src/main/res/layout/activity_main.xml | 9 +++++++ 3 files changed, 49 insertions(+) diff --git a/javasample/src/main/java/com/oursky/authgeartest/MainActivity.java b/javasample/src/main/java/com/oursky/authgeartest/MainActivity.java index 6257ee19..8e990eae 100644 --- a/javasample/src/main/java/com/oursky/authgeartest/MainActivity.java +++ b/javasample/src/main/java/com/oursky/authgeartest/MainActivity.java @@ -65,6 +65,7 @@ public class MainActivity extends AppCompatActivity { private View mChangePassword; private View mDeleteAccount; private View mFetchUserInfo; + private View mRefreshAccessToken; private View mShowAuthTime; private View mLogout; private MainViewModel viewModel; @@ -104,6 +105,7 @@ protected void onCreate(Bundle savedInstanceState) { mChangePassword = findViewById(R.id.changePassword); mDeleteAccount = findViewById(R.id.deleteAccount); mFetchUserInfo = findViewById(R.id.fetchUserInfo); + mRefreshAccessToken = findViewById(R.id.refreshAccessToken); mShowAuthTime = findViewById(R.id.showAuthTime); mLogout = findViewById(R.id.logout); mUseWebKitWebView = findViewById(R.id.useWebKitWebView); @@ -167,6 +169,7 @@ protected void onCreate(Bundle savedInstanceState) { mChangePassword.setOnClickListener(view -> viewModel.openChangePassword()); mDeleteAccount.setOnClickListener(view -> viewModel.openDeleteAccount()); mFetchUserInfo.setOnClickListener(view -> viewModel.fetchUserInfo()); + mRefreshAccessToken.setOnClickListener(view -> viewModel.refreshAccessToken()); mShowAuthTime.setOnClickListener(view -> viewModel.showAuthTime(this)); mLogout.setOnClickListener(view -> viewModel.logout()); @@ -280,6 +283,16 @@ public void onNothingSelected(AdapterView parent) { builder.create().show(); }); + viewModel.refreshAccessTokenResult().observe(this, message -> { + if (message == null) return; + AlertDialog.Builder builder = new AlertDialog.Builder(this); + builder.setTitle("Refresh Access Token If Needed"); + builder.setMessage(message); + builder.setPositiveButton("OK", (dialogInterface, i) -> { + }); + builder.create().show(); + }); + viewModel.error().observe(this, e -> { if (e == null) return; AlertDialog.Builder builder = new AlertDialog.Builder(this); @@ -358,6 +371,7 @@ private void updateButtonDisabledState(MainViewModel viewModel) { mChangePassword.setEnabled(!isLoading && isConfigured && isLoggedIn); mDeleteAccount.setEnabled(!isLoading && isConfigured && isLoggedIn); mFetchUserInfo.setEnabled(!isLoading && isConfigured && isLoggedIn); + mRefreshAccessToken.setEnabled(!isLoading && isConfigured && isLoggedIn); mShowAuthTime.setEnabled(!isLoading && isConfigured && isLoggedIn); mLogout.setEnabled(!isLoading && isConfigured && isLoggedIn); } diff --git a/javasample/src/main/java/com/oursky/authgeartest/MainViewModel.java b/javasample/src/main/java/com/oursky/authgeartest/MainViewModel.java index 65cd8b03..7c3bacb3 100644 --- a/javasample/src/main/java/com/oursky/authgeartest/MainViewModel.java +++ b/javasample/src/main/java/com/oursky/authgeartest/MainViewModel.java @@ -43,6 +43,7 @@ import com.oursky.authgear.OnOpenURLListener; import com.oursky.authgear.OnPromoteAnonymousUserListener; import com.oursky.authgear.OnReauthenticateListener; +import com.oursky.authgear.OnRefreshAccessTokenIfNeededListener; import com.oursky.authgear.OnRefreshIDTokenListener; import com.oursky.authgear.OnWechatAuthCallbackListener; import com.oursky.authgear.OpenAuthorizationURLOptions; @@ -99,6 +100,7 @@ public class MainViewModel extends AndroidViewModel implements AuthgearDelegate final private MutableLiveData mUserInfo = new MutableLiveData<>(null); final private MutableLiveData mSessionState = new MutableLiveData<>(SessionState.UNKNOWN); final private MutableLiveData mError = new MutableLiveData<>(null); + final private MutableLiveData mRefreshAccessTokenResult = new MutableLiveData<>(null); private Intent pendingApp2AppIntent = null; final private MutableLiveData mAuthgearConfigured = new MutableLiveData<>(false); final private MutableLiveData mApp2AppConfirmation = new MutableLiveData<>(null); @@ -239,6 +241,10 @@ public LiveData userInfo() { public LiveData error() { return mError; } + + public LiveData refreshAccessTokenResult() { + return mRefreshAccessTokenResult; + } public LiveData app2appConfirmation() { return mApp2AppConfirmation; } public void configure( @@ -847,6 +853,26 @@ public void onFetchingUserInfoFailed(@NonNull Throwable throwable) { }); } + // Unlike fetchUserInfo(), this does NOT chain any follow-up request + // after refresh, so the refresh result (e.g. invalid_grant vs + // invalid_dpop_proof) is not masked by a subsequent request made with a + // stale/missing access token. + public void refreshAccessToken() { + mAuthgear.refreshAccessTokenIfNeeded(new OnRefreshAccessTokenIfNeededListener() { + @Override + public void onFinished() { + mRefreshAccessTokenResult.setValue( + "Refreshed access token successfully.\nsessionState: " + mAuthgear.getSessionState() + ); + } + + @Override + public void onFailed(Throwable throwable) { + setError(throwable); + } + }); + } + public void showAuthTime(FragmentActivity activity) { Date nullable = mAuthgear.getAuthTime(); if (nullable != null) { diff --git a/javasample/src/main/res/layout/activity_main.xml b/javasample/src/main/res/layout/activity_main.xml index b8d0b174..79694d80 100644 --- a/javasample/src/main/res/layout/activity_main.xml +++ b/javasample/src/main/res/layout/activity_main.xml @@ -586,6 +586,15 @@ android:text="Fetch user info" tools:ignore="HardcodedText" /> +