-
Notifications
You must be signed in to change notification settings - Fork 32
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: Add support for browser-based logins #45
Conversation
This change adds support for specifying an alternative resource directory, allowing resources to be overridden without needing to fork the repository.
This change makes it possible to specify an alternative location for the config.yaml file using an environment variable. This allows the developers to override all important data without messing up any files that can be committed to the repository.
For sites that only support logging in using a third-party login provider, allow logging in via a browser. This new flow will open a custom tab where a user can log in using the supported mechanisms of the site, then have the client id redirect back to to the app using a callback URL. The auth code returned by the callback URL can then be used instead of a username and password to log in.
901f23f
to
91df854
Compare
android { | ||
compileSdk 34 | ||
|
||
defaultConfig { | ||
applicationId "org.openedx.app" | ||
applicationId config?.application_id ?: "org.openedx.app" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Allow customising the applicationId via the config file, but fall back to org.openedx.app as before.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've added some comments to help the reviewer at OpenCraft work on this PR during my leave.
applicationIdSuffix '.dev' | ||
} | ||
stage { | ||
dimension 'env' | ||
applicationIdSuffix '.stage' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added suffixes for each environment since AFAIK this is also done for iOS.
<intent-filter> | ||
<action android:name="android.intent.action.VIEW" /> | ||
<category android:name="android.intent.category.DEFAULT" /> | ||
<category android:name="android.intent.category.BROWSABLE" /> | ||
<data android:scheme="${applicationId}" /> | ||
</intent-filter> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This will have the app handle the scheme matching the applicationId.
i.e. if the application id is "org.openedx.app" then this will handle: com.openedx.app://
private val authCode: String? | ||
get() { | ||
val data = intent?.data | ||
if (data is Uri && data.scheme == BuildConfig.APPLICATION_ID && data.host == "oauth2Callback") { | ||
return data.getQueryParameter("code") | ||
} | ||
return null | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the application was opened using the auth intent filter,
<applicationid>://oauth2Callback?code=<some_code>
it will get the code out of the URL and return that.
val fragment = SignInFragment() | ||
val bundle = Bundle() | ||
bundle.putString("auth_code", authCode) | ||
fragment.arguments = bundle | ||
supportFragmentManager.beginTransaction() | ||
.add(R.id.container, SignInFragment()) | ||
.add(R.id.container, fragment) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pass the code to the login fragment if available.
private suspend fun processAuthResponse(authResponse: AuthResponse) { | ||
if (authResponse.error != null) { | ||
throw EdxError.UnknownException(authResponse.error!!) | ||
} | ||
preferencesManager.accessToken = authResponse.accessToken ?: "" | ||
preferencesManager.refreshToken = authResponse.refreshToken ?: "" | ||
val user = api.getProfile().mapToDomain() | ||
preferencesManager.user = user | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Extracted out the common code since both login functions only have a slightly different API call but the same response.
val authCode = arguments?.getString("auth_code") | ||
if (authCode is String) { | ||
viewModel.login(authCode) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If this view was passed the auth_code then we can just log in straight away.
val intent = CustomTabsIntent.Builder() | ||
.setUrlBarHidingEnabled(true) | ||
.setShowTitle(true) | ||
.build() | ||
intent.launchUrl(context, uri) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using the custom tab mechanism allows any browser to handle this AFAIK and that can use the users saved password etc.
@@ -33,7 +33,7 @@ ext { | |||
firebase_version = "32.1.0" | |||
|
|||
retrofit_version = '2.9.0' | |||
logginginterceptor_version = '4.9.1' | |||
logginginterceptor_version = '4.11.0' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This gets rids of some errors
buildscript { | ||
repositories { | ||
mavenCentral() | ||
maven { | ||
url = uri("https://storage.googleapis.com/r8-releases/raw") | ||
} | ||
} | ||
dependencies { | ||
classpath("com.android.tools:r8:8.2.24") | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This was suggested somewhere on StackOverflow for an error I was getting.
Thanks for the pull request, @xitij2000! Please note that it may take us up to several weeks or months to complete a review and merge your PR. Feel free to add as much of the following information to the ticket as you can:
All technical communication about the code itself will be done via the GitHub pull request interface. As a reminder, our process documentation is here. This is currently a draft pull request. When it is ready for our review and all tests are green, click "Ready for Review", or remove "WIP" from the title, as appropriate. |
@xitij2000 was a product ticket created for this work? We're pushing to have all PRs tie back to a product ticket that is, ideally, prioritized before the development happens. |
I think this PR predates the move to the openedx org. Can a ticket be created now? |
@e0d - flagging this |
Replaced by #190 |
@xitij2000 Even though your pull request wasn’t merged, please take a moment to answer a two question survey so we can improve your experience in the future. |
We were incorrectly sending custom or track events as page events. This update corrects them back to the appropriate event types.
For sites that only support logging in using a third-party login provider, allow logging in via a browser.
This new flow will open a custom tab where a user can log in using the supported mechanisms of the site,
then have the client id redirect back to to the app using a callback URL.
The auth code returned by the callback URL can then be used instead of a username and password to log in.