Skip to content

Return tokens on successful sign in with an IDP #362

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

Merged
merged 5 commits into from
Oct 19, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
import android.widget.TextView;
import com.firebase.ui.auth.AuthUI;
import com.firebase.ui.auth.AuthUI.IdpConfig;
import com.firebase.ui.auth.IdpResponse;
import com.firebase.ui.auth.ui.ResultCodes;
import com.firebase.uidemo.R;
import com.google.android.gms.common.Scopes;
Expand Down Expand Up @@ -128,7 +129,7 @@ public void onCreate(Bundle savedInstanceState) {

FirebaseAuth auth = FirebaseAuth.getInstance();
if (auth.getCurrentUser() != null) {
startActivity(SignedInActivity.createIntent(this));
startActivity(SignedInActivity.createIntent(this, null));
finish();
}

Expand Down Expand Up @@ -219,7 +220,7 @@ private void setFacebookScopesEnabled(boolean enabled) {
@MainThread
private void handleSignInResponse(int resultCode, Intent data) {
if (resultCode == RESULT_OK) {
startActivity(SignedInActivity.createIntent(this));
startActivity(SignedInActivity.createIntent(this, IdpResponse.fromResultIntent(data)));
finish();
return;
}
Expand Down
33 changes: 26 additions & 7 deletions app/src/main/java/com/firebase/uidemo/auth/SignedInActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,12 @@
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;

import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
import com.bumptech.glide.Glide;
import com.firebase.ui.auth.AuthUI;
import com.firebase.ui.auth.IdpResponse;
import com.firebase.uidemo.R;
import com.google.android.gms.tasks.OnCompleteListener;
import com.google.android.gms.tasks.Task;
Expand All @@ -39,14 +42,10 @@
import com.google.firebase.auth.FirebaseAuth;
import com.google.firebase.auth.FirebaseUser;
import com.google.firebase.auth.GoogleAuthProvider;

import java.util.Iterator;

import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;

public class SignedInActivity extends AppCompatActivity {
private static final String EXTRA_IDP_RESPONSE = "extra_idp_response";

@BindView(android.R.id.content)
View mRootView;
Expand Down Expand Up @@ -77,6 +76,7 @@ public void onCreate(Bundle savedInstanceState) {
setContentView(R.layout.signed_in_layout);
ButterKnife.bind(this);
populateProfile();
populateIdpToken();
}

@OnClick(R.id.sign_out)
Expand Down Expand Up @@ -173,15 +173,34 @@ private void populateProfile() {
mEnabledProviders.setText(providerList);
}

private void populateIdpToken() {
IdpResponse idpResponse = getIntent().getParcelableExtra(EXTRA_IDP_RESPONSE);
if (idpResponse != null) {
String token = idpResponse.getIdpToken();
String secret = idpResponse.getIdpSecret();
if (token == null) {
findViewById(R.id.idp_token_layout).setVisibility(View.GONE);
} else {
((TextView) findViewById(R.id.idp_token)).setText(token);
}
if (secret == null) {
findViewById(R.id.idp_secret_layout).setVisibility(View.GONE);
} else {
((TextView) findViewById(R.id.idp_secret)).setText(secret);
}
}
}

@MainThread
private void showSnackbar(@StringRes int errorMessageRes) {
Snackbar.make(mRootView, errorMessageRes, Snackbar.LENGTH_LONG)
.show();
}

public static Intent createIntent(Context context) {
public static Intent createIntent(Context context, IdpResponse idpResponse) {
Intent in = new Intent();
in.setClass(context, SignedInActivity.class);
in.putExtra(EXTRA_IDP_RESPONSE, idpResponse);
return in;
}
}
35 changes: 34 additions & 1 deletion app/src/main/res/layout/signed_in_layout.xml
Original file line number Diff line number Diff line change
Expand Up @@ -90,8 +90,41 @@
android:layout_height="wrap_content" />

</LinearLayout>
</LinearLayout>

<LinearLayout
android:id="@+id/idp_token_layout"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:orientation="vertical">
<TextView
style="@style/Base.TextAppearance.AppCompat.Subhead"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/idp_token"/>

<TextView
android:id="@+id/idp_token"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>

<LinearLayout
android:id="@+id/idp_secret_layout"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:orientation="vertical">
<TextView
style="@style/Base.TextAppearance.AppCompat.Subhead"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/idp_secret"/>

<TextView
android:id="@+id/idp_secret"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>

</LinearLayout>
</ScrollView>
</ScrollView>
2 changes: 2 additions & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -55,4 +55,6 @@
<string name="extra_facebook_scopes">Example extra Facebook scopes</string>
<string name="friends">Friends</string>
<string name="photos">Photos</string>
<string name="idp_token">IDP Token</string>
<string name="idp_secret">IDP Secret</string>
</resources>
18 changes: 18 additions & 0 deletions auth/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,7 @@ startActivityForResult(

#### Handling the sign-in response

#####Response codes
The authentication flow only provides three response codes:
`Activity.RESULT_OK` if a user is signed in, `Activity.RESULT_CANCELLED` if
sign in failed, and `ResultCodes.RESULT_NO_NETWORK` if sign in failed due to a lack of network connectivity.
Expand Down Expand Up @@ -239,6 +240,23 @@ see the
[Firebase Auth documentation](https://firebase.google.com/docs/auth/android/manage-users#get_the_currently_signed-in_user)
for more information.

##### ID Tokens
To retrieve the ID token that the IDP returned, you can extract an `IdpResponse` from the result
Intent.

```java
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == RESULT_OK) {
IdpResponse idpResponse = IdpResponse.fromResultIntent(data);
startActivity(new Intent(this, WelcomeBackActivity.class)
.putExtra("my_token". idpResponse.getIdpToken()));
}
}
```

Twitter also returns an AuthToken Secret which can be accessed with `idpResponse.getIdpSecret()`.

### Sign out

With the integrations provided by AuthUI, signing out a user is a multi-stage process:
Expand Down
4 changes: 2 additions & 2 deletions auth/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
android:label="@string/default_toolbar_title"
android:theme="@style/FirebaseUI.Translucent" />
<activity
android:name="com.firebase.ui.auth.ui.account_link.WelcomeBackIDPPrompt"
android:name="com.firebase.ui.auth.ui.account_link.WelcomeBackIdpPrompt"
android:label="@string/title_welcome_back_idp_prompt"
android:theme="@style/FirebaseUI" />
<activity
Expand All @@ -51,7 +51,7 @@
android:label="@string/default_toolbar_title"
android:theme="@style/FirebaseUI" />
<activity
android:name="com.firebase.ui.auth.ui.idp.IDPSignInContainerActivity"
android:name="com.firebase.ui.auth.ui.idp.IdpSignInContainerActivity"
android:label="@string/default_toolbar_title"
android:theme="@style/FirebaseUI.Translucent" />
<activity
Expand Down
3 changes: 0 additions & 3 deletions auth/src/main/java/com/firebase/ui/auth/AuthUI.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@
import android.support.annotation.VisibleForTesting;
import com.facebook.FacebookSdk;
import com.facebook.login.LoginManager;
import com.firebase.ui.auth.provider.TwitterProvider;
import com.firebase.ui.auth.ui.ChooseAccountActivity;
import com.firebase.ui.auth.ui.FlowParameters;
import com.firebase.ui.auth.ui.idp.AuthMethodPickerActivity;
Expand Down Expand Up @@ -57,8 +56,6 @@
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;

/**
* The entry point to the AuthUI authentication flow, and related utility methods.
Expand Down
123 changes: 123 additions & 0 deletions auth/src/main/java/com/firebase/ui/auth/IdpResponse.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
/*
* Copyright 2016 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.firebase.ui.auth;

import android.content.Intent;
import android.os.Parcel;
import android.os.Parcelable;
import android.support.annotation.Nullable;
import com.firebase.ui.auth.ui.ExtraConstants;

/**
* A container that encapsulates the result of authenticating with an Identity Provider.
*/
public class IdpResponse implements Parcelable {

private final String mProviderId;
@Nullable private final String mEmail;
private final String mToken;
private final String mSecret;

public IdpResponse(String providerId, @Nullable String email) {
this(providerId, email, null, null);
}

public IdpResponse(
String providerId, @Nullable String email, @Nullable String token) {
this(providerId, email, token, null);
}

public IdpResponse(
String providerId,
@Nullable String email,
@Nullable String token,
@Nullable String secret) {
mProviderId = providerId;
mEmail = email;
mToken = token;
mSecret = secret;
}

public static final Creator<IdpResponse> CREATOR = new Creator<IdpResponse>() {
@Override
public IdpResponse createFromParcel(Parcel in) {
return new IdpResponse(
in.readString(),
in.readString(),
in.readString(),
in.readString()
);
}

@Override
public IdpResponse[] newArray(int size) {
return new IdpResponse[size];
}
};

/**
* Get the type of provider. e.g. {@link AuthUI#GOOGLE_PROVIDER}
*/
public String getProviderType() {
return mProviderId;
}

/**
* Get the token received as a result of logging in with the specified IDP
*/
@Nullable
public String getIdpToken() {
return mToken;
}

/**
* Twitter only. Return the token secret received as a result of logging in with Twitter.
*/
@Nullable
public String getIdpSecret() {
return mSecret;
}

/**
* Get the email used to sign in.
*/
@Nullable
public String getEmail() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NonNull? Also is there any case this would not be FirebaseAuth.getInstance().getCurrentUser().getEmail()? Would prefer not to duplicate if so.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's actually nullable (because Twitter always has to be special). We need to record the email on the IdpResponse because we can be in the state where the user has signed in to the IDP but were unable to sign in to Firebase and we need to know the email to to find the existing account to link.

return mEmail;
}

@Override
public int describeContents() {
return 0;
}

@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(mProviderId);
dest.writeString(mEmail);
dest.writeString(mToken);
dest.writeString(mSecret);
}

/**
* Extract the {@link IdpResponse} from the flow's result intent.
* @param resultIntent The intent which {@code onActivityResult} was called with.
* @return The IdpResponse containing the token(s) from signing in with the Idp
*/
@Nullable
public static IdpResponse fromResultIntent(Intent resultIntent) {
return resultIntent.getParcelableExtra(ExtraConstants.EXTRA_IDP_RESPONSE);
}
}
Loading