Kyle
Kyle

Reputation: 1639

How to handle Basic Authentication in WebView

I've created an application which loads a WebView. In order to login, the website requires basic authentication. When i try to access the website via the default browser, I get a pop up box prompting me to enter my user name and password.

If I try to access the website via my application, I get error 401 and no pop up. I was wondering if someone could help me out?

Upvotes: 24

Views: 49287

Answers (6)

M Ayoub Abd
M Ayoub Abd

Reputation: 11

This worked for me add username/pass WebViewClient then setWebViewClient

webView.setWebViewClient(new MyWebViewClient ());

//add this class in main activity 
class MyWebViewClient extends WebViewClient {
    @Override
    public void onReceivedHttpAuthRequest(WebView view,
                                          HttpAuthHandler handler, String host, String realm) {

        handler.proceed("your username", "your password");

    }
}

Upvotes: 1

Padge
Padge

Reputation: 91

I know this is old, but adding another approach here as the ones above (using the onReceivedHttpAuthRequest) didn't work for me. Specifically some web pages don't prompt the user for Basic Authentication, they just redirect to the login screen. In my testing, Grafana happens to have this behavior by default.

So instead I added a HTTP Basic auth header using the below code:

HashMap<String, String> headers = new HashMap<>();
String basicAuthHeader = android.util.Base64.encodeToString((username + ":" + password).getBytes(), android.util.Base64.NO_WRAP);
headers.put("Authorization", "Basic " + basicAuthHeader);
webView.loadUrl(url, headers);

This should bypass the auth prompt and just set the credentials automatically. Hope this helps someone looking for another solution.

Also, for anyone hoping to use the URL pattern of "https://username:password@url" - this is deprecated and I think most browsers will ignore it and throw away the credentials.

edit

I've come to the realization my above solution only works for the first request, and no subsequent requests after the page is loaded (i.e. for any further resources loaded).

In order for all subsequent requests to work, I had to override the following function for the web client:

@Override
public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request){
    if (username != null && password != null && username.length() > 0 && password.length() > 0) {
        try {
            OkHttpClient client = new OkHttpClient();
            Request.Builder newRequestBuilder = new Request.Builder()
                    .url(request.getUrl().toString());

            // add headers
            Map<String, String> currentHeaders = request.getRequestHeaders();
            for (String header : currentHeaders.keySet()){
                newRequestBuilder.addHeader(header, currentHeaders.get(header));
            }
            String basicAuthHeader = android.util.Base64.encodeToString((username + ":" + password).getBytes(), android.util.Base64.NO_WRAP);
            newRequestBuilder.addHeader("Authorization", "Basic "+basicAuthHeader);

            //make request
            Request newRequest = newRequestBuilder.build();
            Response response = client.newCall(newRequest).execute();

            // respond with content
            return new WebResourceResponse(response.header("content-type"), response.header("content-encoding", "utf-8"), response.body().byteStream());
        } catch (Exception e) {
            // if an exception occurs, just make a default request
            return null;
        }
    } else {
        // if no username and password, then make a default request
        return null;
    }
}

Unfortunately this code will not intercept POST requests, only GET requests, which limits what you can do with it.

Further, the above code should have some logic added to verify the domain of the initial request matches the domain of the intercepted requests before attaching the Authorization headers. Otherwise the Authorization header will be sent with all requests which could unintentionally send it to a different domain (e.g. loading resources from a CDN).

Upvotes: 1

aswanth bonthala
aswanth bonthala

Reputation: 261

Use this function onReceivedHttpAuthRequest. It Notifies the host application that the WebView received an HTTP authentication request. The host application can use the supplied HttpAuthHandler to set the WebView's response to the request. The default behavior is to cancel the request.

Below is the sample written in Kotlin

 override fun onReceivedHttpAuthRequest(
            view: WebView,
            handler: HttpAuthHandler,
            host: String,
            realm: String
        ) {
            handler.proceed("username", "password")
        }

Check the Documentation here

Upvotes: 0

Saad Farooq
Saad Farooq

Reputation: 13402

I reckon a more elegant solution than the one Patrick describes would be to use the onReceivedHttpAuthRequest method of WebViewClient as described here: http://www.mail-archive.com/[email protected]/msg30468.html

@Override
public void onReceivedHttpAuthRequest(WebView view, HttpAuthHandler handler, String host, String realm) {
    handler.proceed("username", "password");
}

Upvotes: 43

Patrick Boos
Patrick Boos

Reputation: 7039

The website requires authentication.

First you react to the error:

webview.setWebViewClient(new WebViewClient() {
   public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
     if (errorCode == 401) {
         // show alert to enter username and password
         // then when those are entered in the alert,
         //     set it through the setHttpAuthUsernamePassword(...) shown below
         //     and then reload the site
     }
   }
 });

Use this function to set user and password: WebView.setHttpAuthUsernamePassword()

webview.setHttpAuthUsernamePassword(host, realm, username, password);

All are strings. See the link above for more information on what host and realm means.

Solution found here: Supply some basic auth credentials to a WebView?

Upvotes: 14

NoobTW
NoobTW

Reputation: 2564

public void onReceivedHttpAuthRequest(WebView view, HttpAuthHandler handler, String host, String realm) {
     handler.proceed("USERNAME", "PASSWORD");
}

I think it helpful about the 401 error on WebView.

Upvotes: 11

Related Questions