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>