An abandoned consent screen causes the next authorization request to be rejected with `access_denied` (LINE SDK 5.10.1)
Nobody has claimed this yet.
Assessment
- Difficulty
- 5/5
- Estimated time
- Over a week
- Newbie friendliness
- 25/100
- Issue type
- Bug
- Clarity
- Needs clarification
- Activity status
- Quiet
- Domain
- authentication, mobile
Research direction
Reproduce the abandoned-consent sequence on the stated Android environment, then read BrowserAuthenticationApi#getAuthenticationResultFrom and the LineAuthenticationController cancellation timing mentioned in the report. The issue names no repository file or test; done would require confirming the cause and documenting or implementing a supported way for a new request to supersede or reset the abandoned authorization.
Written by the indexing model from the issue text.
Description
Summary
When integrating LINE Login with the LINE Android SDK, a login attempt that the user leaves without answering the consent screen puts the LINE application into a state where the next authorization request is rejected.
This does not require the user to close or kill anything. Simply pressing Home, switching to another application, or opening Recents and moving to a different task while the consent screen is displayed is enough. The LINE application keeps running, and the consent screen itself is never dismissed.
The next request never shows any UI. It returns access_denied almost immediately, and the SDK reports LineApiResponseCode.CANCEL. Only the request after that succeeds.
From the user's point of view the login button does nothing the first time it is pressed. From the integrating application's point of view the event is indistinguishable from the user declining consent.
Environment
- LINE Android SDK: 5.10.1
- LINE application: 26.13.0
- Login method: App-to-App LINE Login (
botPrompt=aggressive, scopesprofile email openid) - Result handling:
ActivityResultContracts.StartActivityForResult - Device:
- Samsung SM-S931N
- Android 16 (API 36)
- Reproducibility:
- Always reproducible once the consent screen has been abandoned
Steps to Reproduce
- Launch LINE Login from the host application. The LINE application opens the consent screen.
- Without tapping Allow or Cancel, leave LINE with the Home button and return to the host application. The SDK cancels the attempt after about one second, as expected (
LineAuthenticationController.CANCEL_DELAY_MILLIS).
LINE is only backgrounded here — it is not closed, not swiped away from Recents, and its process stays alive. Switching to another application instead of pressing Home produces the same result. - Start LINE Login again.
- Start LINE Login once more.
Expected Behavior
In step 3, the new authorization request should supersede the abandoned one and the consent screen should be displayed.
Actual Behavior
In step 3:
- The LINE application does not become visible at all.
access_deniedis returned after roughly 370 ms.- The SDK reports
LineApiResponseCode.CANCEL. - The callback carries the same parameters as a genuine consent denial.
In step 4 the login proceeds normally. Exactly one request is consumed each time the consent screen is abandoned.
Investigation
All components named below belong to the LINE application package (jp.naver.line.android) and were read from its APK manifest and from dumpsys on a device. None of them are part of the SDK or of the integrating application.
The abandoned consent screen is paused, not destroyed
dumpsys activity activities, immediately after step 2:
Task{#5892 A=jp.naver.line.android visible=false visibleRequested=false sz=2}
mLastPausedActivity: ChannelPermissionApprovalActivity t5892
* Hist #0: ChannelPermissionApprovalActivity
resultTo=OAuthWebLoginServiceActivity resultWho=null resultCode=100
windows=[Window{...ChannelPermissionApprovalActivity}]
The activity is still alive and still owes a result to its parent.
The user cannot return to it
The OAuth task is excluded from Recents. From the LINE application manifest:
| Activity | launchMode |
excludeFromRecents |
|---|---|---|
jp.naver.line.android.urlscheme.service.oauth.OAuthWebLoginServiceActivity |
2 (singleTask) |
true |
jp.naver.line.android.activity.channel.permission.ChannelPermissionApprovalActivity |
(none → standard) | (none) |
Confirmed at runtime:
Recent tasks visible drop reason:
* Task{... A=jp.naver.line.android}
Drop Reason: ACTIVITY_EXCLUDE_FLAG
mCallingPackage=jp.naver.line.android
intent={flg=0x10800000 cmp=.../OAuthWebLoginServiceActivity}
0x10000000 FLAG_ACTIVITY_NEW_TASK
0x00800000 FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
Because excludeFromRecents is set while noHistory is not, the consent screen remains alive but unreachable. It is not listed in Recents, and the launcher icon opens LINE's main task instead. The user has no way to complete or dismiss the pending consent.
The next request is answered by the previous attempt's activity
logcat ActivityTaskManager during step 3:
17:29:58.851 START .../LineAuthenticationActivity
from uid 10566 (host application)
17:29:59.222 START .../LineAuthenticationCallbackActivity
dat=lineauth://result/...
from uid 10595 (jp.naver.line.android) sr=18359843
sr=18359843 identifies the activity that sent the callback:
ActivityRecord{18359843 jp.naver.line.android/.urlscheme.service.oauth.OAuthWebLoginServiceActivity t5892}
This belongs to t5892 — the task created in step 1. No new LINE task was created for the step 3 request, and Task{#5892} disappears entirely right afterwards.
State across the three points:
| Consent screen visible | After Home button | After the step 3 request | |
|---|---|---|---|
Task{#5892} |
visible=true |
visible=false |
gone |
ChannelPermissionApprovalActivity |
topResumedActivity |
mLastPausedActivity |
gone |
resultCode |
100 |
100 |
— |
A possible explanation
OAuthWebLoginServiceActivity is declared singleTask. When a new authorization intent is routed to it, the platform destroys every activity stacked above the existing instance before delivering onNewIntent().
The activity destroyed that way is ChannelPermissionApprovalActivity, which was started with startActivityForResult and had a result pending. Its destruction delivers RESULT_CANCELED to OAuthWebLoginServiceActivity.
The instance therefore receives the new authorization request and a cancellation of the previous consent at effectively the same moment, and the cancellation appears to take precedence.
Two observations are consistent with this:
- The error is specifically
access_denied, the code for a declined consent, rather than a generic failure. - The SDK validates
statebefore parsingerrorinBrowserAuthenticationApi#getAuthenticationResultFrom, and the result is a cleanCANCELrather thanIllegal parameter value of 'state'. The new request'sstatewas therefore adopted, which suggests the new intent was read before the flow was discarded.
We can only observe this from outside the LINE application, so this part is an inference rather than a confirmed cause.
Impact
Integrating applications cannot distinguish this from a real consent denial. The callback parameters are identical, and the SDK maps both to LineApiResponseCode.CANCEL. Any application that measures its login funnel will count these as user denials.
There is also no way for an integrator to detect or clear the pending state, since the task belongs to the LINE application and is excluded from Recents.
Questions
- Is this behaviour expected when a previous authorization has been left unanswered?
- Should a new authorization request supersede a pending one, rather than being rejected by it?
- Is there a supported way for an integrating application to detect or reset this state?
- Is there a recommended implementation pattern for applications where users frequently switch away during consent?
Additional Notes
The 4.0.2 release notes list a known issue with the same user-visible symptom — onActivityResult returning CANCEL on the first login attempt with app-to-app login, succeeding on the second — which was fixed in 4.0.4 and scoped to Android 4.x. The cause described here appears to be different, but the symptom users experience is the same.
Possibly related open issues: #138, #140, #171, #192.
Thank you.
- Dominant language
- Java
- Stars
- 149
- Forks
- 55
- PR merge metrics
- No merged PRs in 30d
Getting set up
- No Dockerfile or Docker Compose file
- No pull request template
- Read the contributing guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from line/line-sdk-android
-
Difficulty 4/5 3-5 days Newbie friendliness 18/100
line/line-sdk-android#194 ·
-
Difficulty 5/5 Over a week Newbie friendliness 25/100
line/line-sdk-android#192 ·
-
Difficulty 3/5 1-2 days Newbie friendliness 45/100
line/line-sdk-android#185 · 1 comment · 1 reaction ·
-
Difficulty 4/5 3-5 days Newbie friendliness 38/100
line/line-sdk-android#179 · 1 comment ·
-
Difficulty 5/5 Over a week Newbie friendliness 20/100
line/line-sdk-android#176 ·
All issues in line/line-sdk-android
Similar issues
-
Difficulty 2/5 1-3 hours Newbie friendliness 66/100
wultra/powerauth-tests#980 ·
-
account bug communication lecture
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
line/centraldogma#1397 ·
Maintainers usually reply within 2 days
-
[Bug]: Fixed/recurring deposit accounts are treated as savings in ownership and listingsPossibly taken @Aana123 claimed this today. Openbug Triage
Difficulty 2/5 1-3 hours Newbie friendliness 76/100
apache/fineract-consumer-facing#252 ·
Maintainers usually reply within 1 day
-
Difficulty 1/5 Under an hour Newbie friendliness 78/100
cryptomator/hub#515 ·