Custom login fragment example
public class JwtAuthManagerJava implements AuthLoginManager {
private static final String NETWORK_NAME = "YOUR_NETWORK_NAME";
private String currentEmail = null;
private ObservableCallback<Credential> observableCallback;
@Override
public Observable<Credential> login(final Context context) {
observableCallback = new ObservableCallback<Credential>();
ActivityUtil.getAppCompatActivity(context).
getSupportFragmentManager().
beginTransaction().
setCustomAnimations(android.R.anim.fade_in, android.R.anim.fade_in).
addToBackStack("LOGIN").
replace(android.R.id.content, new CustomLoginFragment()).
commit();
return observableCallback.asObservable();
}
public ObservableCallback<Credential> getObservable(){
return observableCallback;
}
@Override
public Observable<SimpleUser> register(Context context, @Nullable String email) {
return Observable.just(SimpleUser.Builder.init("FirstName", "LastName", currentEmail).create());
}
@Override
public Credential refreshToken(Context context) {
if (currentEmail == null) {
VouchrSDK.userManager().logout();
return null;
} else {
return new Credential(NETWORK_NAME, getJWT(currentEmail));
}
}
public void setEmail(String email){
currentEmail = email;
}
@Override
public void logout(Context context) {
}
@Override
public LoginInfo getNetworkInfo() {
return new LoginInfo(NETWORK_NAME, false, "Voucher SDK JWT Login");
}
// CRITICAL: for production uses, jwt must be created/signed by partner login service, not created locally and should be encrypted
// If you are using this local JWT for testing, select your application, then go to Dashboard / Developer / Authentication and set the authentication's Signature Type to NONE
private String getJWT(String username) {
JSONObject header = new JSONObject();
try {
header.put("alg", "none");
header.put("type", "jwt");
JSONObject claims = new JSONObject();
claims.put("sub", username);
claims.put("email", username);
claims.put("email_verified", true);
StringBuilder sb = new StringBuilder();
sb.append(new String((toBase64(header.toString(), Base64.URL_SAFE)), Charset.defaultCharset()));
sb.append(".");
sb.append(new String((toBase64(claims.toString(), Base64.URL_SAFE)), Charset.defaultCharset()));
return sb.toString();
} catch (JSONException e) {
e.printStackTrace();
return null;
}
}
private byte[] toBase64(String string, int flags) {
byte[] bytes = string.getBytes(Charset.defaultCharset());
return Base64.encode(bytes, flags);
}
}
class JwtAuthManager(private val networkName: String = "YOUR_NETWORK_NAME") : AuthLoginManager {
private var currentEmail: String? = null
private var observableCallback: ObservableCallback<Credential> = ObservableCallback<Credential>()
override fun login(context: Context): Observable<Credential> {
observableCallback = ObservableCallback<Credential>()
ActivityUtil.getAppCompatActivity(context).
supportFragmentManager.
beginTransaction().
setCustomAnimations(android.R.anim.fade_in, android.R.anim.fade_in).
addToBackStack("LOGIN").
replace(android.R.id.content, CustomLoginFragment()).
commit()
return observableCallback.asObservable()
}
fun getObservable(): ObservableCallback<Credential> {
return observableCallback
}
override fun register(context: Context, email: String?): Observable<SimpleUser>? {
return Observable.just(SimpleUser.Builder.init("FirstName", "LastName", currentEmail).create())
}
override fun refreshToken(context: Context): Credential? {
if (currentEmail == null) {
VouchrSDK.userManager().logout()
return null
} else {
return Credential(networkName, getJWT(currentEmail!!))
}
}
fun setEmail(email: String) {
currentEmail = email
}
override fun logout(context: Context) {
}
override fun getNetworkInfo(): LoginInfo? {
return LoginInfo(networkName, false, "Voucher SDK JWT Login")
}
// CRITICAL: for production uses, jwt must be created/signed by partner login service, not created locally and should be encrypted
// If you are using this local JWT for testing, select your application, then go to Dashboard / Developer / Authentication and set the authentication's Signature Type to NONE
private fun getJWT(username: String): String {
val header = JSONObject()
header.put("alg", "none")
header.put("type", "jwt")
val claims = JSONObject()
claims.put("sub", username)
claims.put("email", username)
claims.put("email_verified", true)
val sb = StringBuilder()
sb.append(header.toString().toBase64(Base64.URL_SAFE).toString(Charset.defaultCharset()))
sb.append(".")
sb.append(claims.toString().toBase64(Base64.URL_SAFE).toString(Charset.defaultCharset()))
return sb.toString()
}
private fun String.toBase64(flags: Int = Base64.DEFAULT): ByteArray {
val bytes = this.toByteArray(Charset.defaultCharset())
return Base64.encode(bytes, flags)
}
}
public class CustomLoginFragmentJava extends Fragment {
@BindView(R.id.btnLogin)
protected VouchrButton btnLogin;
@BindView(R.id.close_btn)
protected VouchrButton btnClose;
@BindView(R.id.inputPassword)
protected SensitiveInfoEditText inputPassword;
@BindView(R.id.inputEmail)
protected SensitiveInfoEditText inputEmail;
private String networkName = "JWT_TEST";
private JwtAuthManager jwt;
private Boolean logged = false;
public CustomLoginFragmentJava() {
// Required empty public constructor
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
jwt = (JwtAuthManager) Engine.userManager().getAuthManagerForNetworkName(networkName);
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
btnLogin.setOnClickListener((View v) -> {
login();
});
btnClose.setOnClickListener((View v) -> {
getActivity().getSupportFragmentManager().popBackStack("LOGIN", FragmentManager.POP_BACK_STACK_INCLUSIVE);
});
inputPassword.setTransformationMethod(new PasswordTransformationMethod());
}
@Override
public void onDestroy() {
if (!logged) {
ObservableCallback<Credential> observableCallback = jwt.getObservable();
observableCallback.onError(new Exception("Canceled"));
}
super.onDestroy();
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_custom_login, null);
ButterKnife.bind(this, view);
return view;
}
public void login() {
ObservableCallback<Credential> observableCallback = jwt.getObservable();
String email = inputEmail.getText().toString();
String password = inputPassword.getText().toString();
if (email.isEmpty()) {
Toast.makeText(getContext(), "Need to enter info", Toast.LENGTH_LONG).show();
return;
} else {
Credential credential = new Credential(networkName, getJWT(email.toLowerCase()));
jwt.setEmail(email);
observableCallback.onSuccess(credential);
logged = true;
getActivity().getSupportFragmentManager().popBackStack("LOGIN", FragmentManager.POP_BACK_STACK_INCLUSIVE);
}
}
// CRITICAL: for production uses, jwt must be created/signed by partner login service, not created locally and should be encrypted
// If you are using this local JWT for testing, select your application, then go to Dashboard / Developer / Authentication and set the authentication's Signature Type to NONE
private String getJWT(String username) {
JSONObject header = new JSONObject();
try {
header.put("alg", "none");
header.put("type", "jwt");
JSONObject claims = new JSONObject();
claims.put("sub", username);
claims.put("email", username);
claims.put("email_verified", true);
StringBuilder sb = new StringBuilder();
sb.append(new String((toBase64(header.toString(), Base64.URL_SAFE)), Charset.defaultCharset()));
sb.append(".");
sb.append(new String((toBase64(claims.toString(), Base64.URL_SAFE)), Charset.defaultCharset()));
return sb.toString();
} catch (JSONException e) {
e.printStackTrace();
return null;
}
}
private byte[] toBase64(String string, int flags) {
byte[] bytes = string.getBytes(Charset.defaultCharset());
return Base64.encode(bytes, flags);
}
}
class CustomLoginFragment : Fragment() {
private val networkName: String = "JWT_TEST"
private lateinit var jwt: JwtAuthManager
private var logged: Boolean = false
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
jwt = Engine.userManager().getAuthManagerForNetworkName(networkName) as JwtAuthManager
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
btnLogin.setOnClickListener { login() }
closeBtn.setOnClickListener { activity!!.supportFragmentManager.popBackStack("LOGIN", FragmentManager.POP_BACK_STACK_INCLUSIVE) }
inputPassword.transformationMethod = PasswordTransformationMethod()
}
fun login() {
var observableCallback = jwt.getObservable()
val email = inputEmail?.text.toString()
val password = inputPassword?.text.toString()
if (email.isNullOrEmpty()) {
Toast.makeText(context, "Need to enter info", Toast.LENGTH_LONG).show()
return
} else {
val credential = Credential(networkName, getJWT(email.toLowerCase()))
jwt.setEmail(email)
observableCallback.onSuccess(credential)
logged = true
activity!!.supportFragmentManager.popBackStack("LOGIN", FragmentManager.POP_BACK_STACK_INCLUSIVE)
}
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.fragment_custom_login, null)
}
override fun onDestroy() {
if (!logged) {
var observableCallback = jwt.getObservable()
observableCallback.onError(Exception("Canceled"))
}
super.onDestroy()
}
// CRITICAL: for production uses, jwt must be created/signed by partner login service, not created locally and should be encrypted
// If you are using this local JWT for testing, select your application, then go to Dashboard / Developer / Authentication and set the authentication's Signature Type to NONE
private fun getJWT(username: String): String {
val header = JSONObject()
header.put("alg", "none")
header.put("type", "jwt")
val claims = JSONObject()
claims.put("sub", username)
claims.put("email", username)
claims.put("email_verified", true)
val sb = StringBuilder()
sb.append(header.toString().toBase64(Base64.URL_SAFE).toString(Charset.defaultCharset()))
sb.append(".")
sb.append(claims.toString().toBase64(Base64.URL_SAFE).toString(Charset.defaultCharset()))
return sb.toString()
}
private fun String.toBase64(flags: Int = Base64.DEFAULT): ByteArray {
val bytes = this.toByteArray(Charset.defaultCharset())
return Base64.encode(bytes, flags)
}
}
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="?vchr_ScreenBackground"
android:backgroundTint="?android:colorBackground"
android:clickable="true"
android:fitsSystemWindows="true"
android:orientation="vertical">
<com.surpriise.vouchrcommon.ui.components.VouchrButton
android:id="@+id/closeBtn"
style="?VouchrButton.CloseButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingLeft="24dp"
android:paddingTop="24dp"
android:paddingRight="24dp">
<FrameLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:clipToPadding="false"
android:paddingHorizontal="60dp">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_logo"
android:tint="@color/white"
android:translationX="4dp" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_logo"
android:tint="?colorAccent" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_logo"
android:tint="?colorPrimary"
android:translationX="-4dp" />
</FrameLayout>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="Email"
android:textAppearance="?TextAppearance.Body"></TextView>
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/emailWrapper"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.surpriise.vouchrcommon.ui.components.SensitiveInfoEditText
android:id="@+id/inputEmail"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAppearance="?TextAppearance.Body" />
</com.google.android.material.textfield.TextInputLayout>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="Password"
android:textAppearance="?TextAppearance.Body"></TextView>
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/passwordWrapper"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.surpriise.vouchrcommon.ui.components.SensitiveInfoEditText
android:id="@+id/inputPassword"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textPassword" />
</com.google.android.material.textfield.TextInputLayout>
<com.surpriise.vouchrcommon.ui.components.VouchrButton
android:id="@+id/btnLogin"
style="?VouchrButton.Positive"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="40dp"
android:layout_marginBottom="24dp"
android:padding="12dp"
android:text="Login" />
</LinearLayout>