23

I'm trying to do basic authentication to view a protected url. I want to access the protected url which looks like this:

http://api.test.com/userinfo/vid?=1234

So I do the following with a WebView:

mWebView.setHttpAuthUsernamePassword("api.test.com", "", "me@test.com", "mypassword");
mWebView.loadUrl("http://api.test.com/userinfo/user?uid=53461");

but the authentication doesn't seem to work, I'm just getting an output error page. Am I using the WebView method correctly here?

Update: Trying with curl:

curl -u me@test.com:mypassword http://api.test.com/userinfo/user?uid=53461

and it pulls the page fine. I tried every combination of the host parameter, the owners of the api don't know what I mean by 'realm' though (and neither do I) - what info could I give them to help this along?

Thanks

user246114
  • 50,223
  • 42
  • 112
  • 149
  • 1
    Where have you defined the protection, the htaccess file? You might want to try out the full path to the folder `http://api.test.com/userinfo/` – Pentium10 Apr 06 '10 at 13:37
  • else u have to set permission tag on AndroidManifest file. – Praveen Apr 06 '10 at 13:41

8 Answers8

101

Another option is to use a WebViewClient;

webview.setWebViewClient(new MyWebViewClient ());

private class MyWebViewClient extends WebViewClient {
@Override
public void onReceivedHttpAuthRequest(WebView view,
        HttpAuthHandler handler, String host, String realm) {

    handler.proceed("me@test.com", "mypassword");

}
}
dparnas
  • 4,090
  • 4
  • 33
  • 52
  • 3
    yes please mark this. this worked here whereas mWebView.setHttpAuthUsernamePassword did not. – Max Hille Feb 08 '12 at 08:28
  • Great! This worked for proxy authentication on my company wifi network. – bob Oct 24 '13 at 01:20
  • 2
    So I suppose I need to make a custom view to ask for credentials? that's dumb – Nicholas Franceschina Oct 02 '14 at 15:05
  • 3
    I discourage using this method. If you supply a wrong user name or password the authentication fails and webview keeps on retrying for auth. This was creating repeated api calls on my server which ended up server getting down. You may consider using a retry counter and WebView.stopLoading() method to avoid infinite looping. – Ajith M A Jun 23 '15 at 15:01
8
webview.setWebViewClient(new WebViewClient () {

    public void onReceivedHttpAuthRequest(WebView view,
            HttpAuthHandler handler, String host, String realm) {

        handler.proceed("login", "pass");
    }
});
Reto Koradi
  • 53,228
  • 8
  • 93
  • 133
Dmitry
  • 81
  • 1
  • 1
  • 1
    I discourage using this method. If you supply a wrong user name or password the authentication fails and webview keeps on retrying for auth. This was creating repeated api calls on my server which ended up server getting down. You may consider using a retry counter and WebView.stopLoading() method to avoid infinite looping. – Ajith M A Jun 23 '15 at 15:01
7

The default behavior of a WebView is to discard all authentication requests. Even if setHttpAuthUsernamePassword.

You have to set a WebViewClient and Override the method onReceivedHttpAuthRequest

user1825382
  • 101
  • 1
  • 1
4

If you do not mind writing your username and password into the url, then it is not necessary to change your webview client.

Just open the following url in the webview:

http://username:password@api.test.com/userinfo/vid?=1234
Fabi
  • 153
  • 1
  • 6
1

In this example realm is By Invitation Only

AuthType Basic
AuthName "By Invitation Only"
AuthUserFile /usr/local/apache/passwd/passwords
Require user rbowen sungo
Pentium10
  • 204,586
  • 122
  • 423
  • 502
  • Hi Pentium, where are you getting this example from though? – user246114 Apr 07 '10 at 21:41
  • 1
    The AuthName directive sets the Realm to be used in the authentication. The realm serves two major functions. First, the client often presents this information to the user as part of the password dialog box. Second, it is used by the client to determine what password to send for a given authenticated area. http://httpd.apache.org/docs/2.0/howto/auth.html – Pentium10 Apr 07 '10 at 21:53
  • This worked for me. Set my realm (discovered with curl -I hostname) and I'm good to go. The webviewclient trick doesn't seem to play well with phonegap (ymmv). – jettero Jul 10 '12 at 01:51
0

I never did get setHttpAuthUsernamePassword to work with phonegap's FileTransfer.download (since it doesn't use the webview), but I DID get this to work with phonegap. It's worth noting if any other phonegap people end up on this thread.

    Authenticator.setDefault(new Authenticator() {
        protected PasswordAuthentication getPasswordAuthentication() {
            return new PasswordAuthentication(user, pass.toCharArray());
        }
    });
jettero
  • 835
  • 2
  • 13
  • 26
0

You may need something other than "" for the second parameter. Contact the developer of the Web site and find out what an appropriate realm should be. Or, use tools like curl to find out what the realm should be.

CommonsWare
  • 986,068
  • 189
  • 2,389
  • 2,491
  • Ok so I tried with curl and it works fine when supplying just username + password - udpated the Q, not sure why it still doesn't want to work? – user246114 Apr 07 '10 at 18:36
0

This is so silly. I hacked something together that worked for me, I hope it'll work for you too.

public class AuthRequestDialogFragment extends DialogFragment
{
    @InjectView(R.id.dauth_userinput)
    public EditText userinput;

    @InjectView(R.id.dauth_passinput)
    public EditText passinput;

    @OnClick(R.id.dauth_login)
    public void login(View view) {
        ((Callback) getTargetFragment()).login(userinput.getText().toString(), passinput.getText().toString());
        this.dismiss();
    }

    @OnClick(R.id.dauth_cancel)
    public void cancel(View view) {
        ((Callback) getTargetFragment()).cancel();
        this.dismiss();
    }

    public static interface Callback
    {
        public void login(String username, String password);
        public void cancel();
    }

    @Override
    public void onStart() {
        super.onStart();
        WindowManager wm = (WindowManager) getActivity().getSystemService(Context.WINDOW_SERVICE);
        Display display = wm.getDefaultDisplay();
        int width = display.getWidth();
        int height = display.getHeight();

        getDialog().getWindow().setLayout(width*2/3, height/5*2);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
    {
        View view = inflater.inflate(R.layout.dialog_authrequest, container);
        ButterKnife.inject(this, view);
        getDialog().setTitle("Authorization required");
        return view;
    }
}

And

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content">
    <TextView
        android:id="@+id/dauth_requsertext"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="The server requires a username and password."
        android:layout_alignParentTop="true"
        android:layout_alignParentStart="true"
        android:layout_alignParentLeft="true"
        android:layout_marginLeft="15dp"
        android:layout_marginStart="15dp"
        android:layout_marginTop="15dp"/>


    <RelativeLayout
        android:id="@+id/dauth_centercontainer"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true">
        <TextView
            android:id="@+id/dauth_usertext"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Username"
            android:layout_alignParentTop="true"
            android:layout_alignParentStart="true"
            android:layout_alignParentLeft="true"
            android:layout_marginLeft="15dp"
            android:layout_marginStart="15dp"
            android:layout_marginTop="15dp"/>
        <TextView
            android:id="@+id/dauth_passtext"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="20dp"
            android:text="Password"
            android:layout_below="@+id/dauth_usertext"
            android:layout_alignLeft="@+id/dauth_usertext"
            android:layout_alignStart="@+id/dauth_usertext"/>
        <EditText
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:id="@+id/dauth_userinput"
            android:ems="12"
            android:layout_alignBottom="@+id/dauth_usertext"
            android:layout_toRightOf="@id/dauth_usertext"
            android:layout_toEndOf="@id/dauth_usertext"/>
        <EditText
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:id="@+id/dauth_passinput"
            android:layout_marginTop="20dp"
            android:inputType="textPassword"
            android:ems="12"
            android:layout_alignBottom="@+id/dauth_passtext"
            android:layout_toRightOf="@id/dauth_passtext"
            android:layout_toEndOf="@id/dauth_passtext"
            android:layout_alignLeft="@id/dauth_userinput"
            android:layout_alignStart="@id/dauth_userinput"/>

    </RelativeLayout>

    <Button
        android:id="@+id/dauth_cancel"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Cancel"
        android:layout_alignParentBottom="true"
        android:layout_alignParentRight="true"
        android:layout_alignParentEnd="true"
        android:layout_marginBottom="15dp"
        android:layout_marginRight="15dp"
        android:layout_marginEnd="15dp"/>


    <Button
        android:id="@+id/dauth_login"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Log In"
        android:layout_alignTop="@+id/dauth_cancel"
        android:layout_marginRight="15dp"
        android:layout_marginEnd="15dp"
        android:layout_toLeftOf="@+id/dauth_cancel"/>



</RelativeLayout>

And

public class WebViewFragment extends Fragment implements AuthRequestDialogFragment.Callback {

    @Override
    public void login(String username, String password) {
        Log.d(this.getClass().getName(), "Login");
        myWebViewClient.login(username, password);
    }

    @Override
    public void cancel() {
        Log.d(this.getClass().getName(), "Cancel");
        myWebViewClient.cancel();
    }

And the most important:

private class MyWebViewClient extends WebViewClient {
    private WebView myView;
    private HttpAuthHandler httpAuthHandler;
    private String host;
    private String realm;

    @Override
    public void onReceivedHttpAuthRequest(WebView view, HttpAuthHandler handler, String host, String realm) {
        AuthRequestDialogFragment authRequestDialogFragment = new AuthRequestDialogFragment();
        FragmentManager fragmentManager = ((getActivity()).getSupportFragmentManager());
        authRequestDialogFragment.setTargetFragment(WebViewFragment.this, 0);
        authRequestDialogFragment.show(fragmentManager, "dialog");
        this.httpAuthHandler = handler;
        this.myView = view;
        this.host = host;
        this.realm = realm;
    }

    public void login(String username, String password) {
        httpAuthHandler.proceed(username, password);
        myView = null;
        httpAuthHandler = null;
        host = null;
        realm = null;
    }

    public void cancel() {
        super.onReceivedHttpAuthRequest(myView, httpAuthHandler, host, realm);
        myView = null;
        httpAuthHandler = null;
        host = null;
        realm = null;
    }
}

Uses dependency:

compile 'com.jakewharton:butterknife:6.0.0'
EpicPandaForce
  • 79,669
  • 27
  • 256
  • 428