-
Notifications
You must be signed in to change notification settings - Fork 1.9k
Add support for GitHub IDP #1199
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
Conversation
Oh, and I forgot to mention that the build is going to fail because of translation issues. @samtstern Could you possibly kick off that process for these strings: https://github.com/firebase/FirebaseUI-Android/pull/1199/files#diff-059a92f7313626f64a0470b20e08afa4? |
Signed-off-by: Alex Saveau <[email protected]>
# Conflicts: # auth/src/main/java/com/firebase/ui/auth/data/remote/SignInKickstarter.java # auth/src/main/java/com/firebase/ui/auth/ui/HelperActivityBase.java # auth/src/main/java/com/firebase/ui/auth/util/ExtraConstants.java
Signed-off-by: Alex Saveau <[email protected]>
Signed-off-by: Alex Saveau <[email protected]>
Signed-off-by: Alex Saveau <[email protected]>
Signed-off-by: Alex Saveau <[email protected]>
# Conflicts: # auth/src/main/java/com/firebase/ui/auth/viewmodel/RequestCodes.java
# Conflicts: # library/quality/quality.gradle
# Conflicts: # auth/build.gradle # auth/src/main/res/values/styles.xml
# Conflicts: # auth/build.gradle # library/quality/quality.gradle
Signed-off-by: Alex Saveau <[email protected]>
Signed-off-by: Alex Saveau <[email protected]>
@samtstern Think we can get the ball rolling on this one? |
@SUPERCILEX sure, happy to get this one back on track. |
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.
Just some first-pass comments.
|
||
private interface GitHubOAuth { | ||
@POST(KEY_ACCESS_TOKEN) | ||
Call<JsonObject> getAuthToken(@Header("Accept") String header, |
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.
Can we get stronger typing than JsonObject
here?
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.
WHAT!!!? How has no one ever told me about this before now??? For some reason, it never clicked that I could use something other than JsonObject
. 🤦♂️ Heck, I even use Gson to deserialize objects outside of Retrofit! Well, time to go update my projects again. 😆 @samtstern Thanks a ton for jostling those brain cells around! ❤️
TL;DR: yes. 👍
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.
Hah that's funny that you didn't know because in my mind that's all Retrofit is good for!
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.
Haha, yeah, I realize that now. 😊
.enableUrlBarHiding() | ||
.setToolbarColor(ContextCompat.getColor(this, R.color.colorPrimary)) | ||
.build() | ||
.launchUrl(this, (Uri) getIntent().getParcelableExtra(ExtraConstants.PARAMS)); |
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.
We're casting the whole PARAMS
to a Uri
? Maybe it should come with a different ExtraConstants
key?
if (mShouldCloseCustomTab) { // User pressed back | ||
finish(RESULT_CANCELED, null); | ||
} | ||
mShouldCloseCustomTab = true; |
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.
Can you explain a little why this is set to true
on each onResume
?
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.
Yeah, I'll explain this and the recursive launch comment below. Basically, I've copied-ish all of this from Facebook since they actually did a really nice job with CCT. So here's what we're trying to do:
- Launch CCT
- If user presses back, close resources related to CCT
- Same for success and failure, but send result data too
Given that CCT is going to redirect to our activity, we need a wrapper with special stuff like singleTop
and ignored config changes so the stack doesn't nest itself. Now that we're guaranteed to have a single activity with a CCT layer on top, we can safely assume that onCreate
is the only place to start CCT. So the current flow looks like this:
- Launch CCT in
onCreate
- Receive redirects in
onNewIntent
That creates a problem though: how do we close CCT? Android doesn't give you a nice way to close all activities on top of the stack AFAIK, so we're force to relaunch our wrapper activity with the CLEAR_TOP
flag. That will recurse while killing CCT to bring us back to onNewIntent
again where we check for the refresh action. At that point, we can finally finish with our result.
Now for the onResume
stuff. Remember how we always have a CCT layer on top? That means onResume
will only ever be called once... unless the user presses back. At that point, our wrapper activity gains focus for the second time and we can safely kill it knowing it was a back event.
Whew! 😌 I realize that's a painful explanation. I dunno, Facebook's code was even more complicated and took me forever to even distill down to this point. They had 2 activities they were juggling around—never understood why. Anyway, if you have any ideas to simplify this stuff, please send them over! 😄
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.
That's all super cool! Can you just encode some of this in code comments? If you want you can literally copy what you just said to a class-level comment.
.putExtra(GitHubSignInHandler.KEY_GITHUB_CODE, code); | ||
} | ||
|
||
// Force a recursive launch to clear the Custom Tabs activity |
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.
What's going on here?
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.
See #1199 (comment)
auth/src/main/res/values/config.xml
Outdated
tools:ignore="ResourceName"> | ||
<resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="ResourceName"> | ||
<!-- Get access to the google-services project id. --> | ||
<item name="project_id" type="string"/> |
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.
What does adding this item
tag do?
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.
Oh boy, forgot about that. Time to remove my hacks and write some docs! 😉
So you added your project URL to the app config.xml and the asset links have the correct SHA-256? Usually, the non redirect means the hash doesn't match up with how the app was signed. FYI gonna wait to see how you get through this to address your feedback 👍. |
Oh, just saw your edit, gimme a sec |
@samtstern can you check the app module's merged manifest? Is the value being pulled in or is lint just mad? |
Here's what I see in the merged manifest: $ cat app/build/intermediates/merged_manifests/debug/processDebugManifest/merged/AndroidManifest.xml | grep -B1 -A15 GitHub
<activity
android:name="com.firebase.ui.auth.ui.provider.GitHubLoginActivity"
android:configChanges="keyboard|keyboardHidden|screenLayout|screenSize|orientation"
android:label=""
android:launchMode="singleTop"
android:theme="@style/FirebaseUI.Transparent" >
<intent-filter android:autoVerify="true" >
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:host="@string/firebase_web_host"
android:path="/__/auth/handler"
android:scheme="https" />
</intent-filter> Which looks fine to me? I don't think it should be a string literal at that point. |
Oh yeah, sorry, I guess you'll have to use the APK analyzer to see the finished product. |
@SUPERCILEX here's what I see in APK analyzer: <activity
android:theme="@ref/0x7f0f00d4"
android:label="@string/0x21"
android:name="com.firebase.ui.auth.ui.provider.GitHubLoginActivity"
android:launchMode="1"
android:configChanges="0x5b0">
<intent-filter
android:autoVerify="true">
<action
android:name="android.intent.action.VIEW" />
<category
android:name="android.intent.category.DEFAULT" />
<category
android:name="android.intent.category.BROWSABLE" />
<data
android:scheme="https"
android:host="@ref/0x7f0e005f"
android:path="/__/auth/handler" />
</intent-filter>
</activity> And for comparison, Facebook: <activity
android:theme="@ref/0x7f0f01b6"
android:label="@ref/0x7f0e001f"
android:name="com.facebook.FacebookActivity"
android:configChanges="0x5b0" />
<activity
android:name="com.facebook.CustomTabActivity"
android:exported="true">
<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="@ref/0x7f0e005a" />
</intent-filter>
</activity> So this may be a red herring. |
If I hardcode the value in
Edit: Ignore this, I think this was a debugging artifact. |
So is the custom tab just closing itself? Or is it still stuck at the redirect URI? I'm pretty sure your Sha hash is wrong... |
Actually, if you want to test that the activity is at least registered correctly, click the open in chrome menu option when you're in the CCT. It should let you choose between chrome or FUI. |
Now the CCT just closes itself. One interesting log line that appears:
Edit: I think that's unrelated Facebook junk. |
Mmmm... So if you go to your GitHub settings and revoke the tokens then log in, it brings you straight back to FUI (not the redirect URI)? |
I think this is just a typo. I did |
Nooooooooooooooo!!! Sam! 😂 |
I got it to work! Well I had to do the "Three Dots > Open In App > (select demo app)" but then it not only signed in with Github but also linked to my existing email/password account and perfectly updated the profile picture. Very impressed. So remaining action items:
Update: Tried this on a fresh device and (1) is not an issue at all. |
Woot! 👏🍾 Yeah, I still want to improve the docs with your feedback and add a "WTF!? It's not working" section 😂 |
Signed-off-by: Alex Saveau <[email protected]>
Signed-off-by: Alex Saveau <[email protected]>
@samtstern The last two commits include a bunch of docs improvements, what do you think? |
@SUPERCILEX those are great! Final thing: let's just tone down the Github section a little bit to make it less scary. Removing things like "It's Github's fault" and "shooting yourself in the foot". Google has a really good relationship with Github and I don't wanna be out here criticizing them, even though it's good-natured. |
Haha, yeah, it could be taken the wrong way. 👍 |
Signed-off-by: Alex Saveau <[email protected]>
@SUPERCILEX good to go! |
Side note: I actually got into contact with GitHub yesterday, and they pointed me to the OAuth spec they use with the security reasons behind their decision (which I've linked to in the README)—really interesting stuff. In any case, I pointed out that the spec does allow configuring multiple redirect URIs so they were kind enough to put that on the backlog... Down the road, we might be able to simplify all this! 👏 TL;DR: I wasn't really being fair anyway now that I understand their reasoning. 😊 |
Awesome sauce! And there aren't even any conflicts with #1358. 🙌 |
@SUPERCILEX that's good to hear that you got in contact with them. Also congrats on the first big feature on top of the new architecture. Very impressive how it scaled. |
Thanks! Yeah, I'm super happy we didn't get stuck at that 95%. 😉 |
Fixes #346
@samtstern Alright, I'm so pumped right now! I figured out how to get GitHub working and I proved the flexibility and scalability of the new architecture—die two birds with my one stone! ☠️😆
Anyway, ignore this PR for now since I've already got you saturated everywhere else.