141

How do I connect to a remote URL in Java which requires authentication. I'm trying to find a way to modify the following code to be able to programatically provide a username/password so it doesn't throw a 401.

URL url = new URL(String.format("http://%s/manager/list", _host + ":8080"));
HttpURLConnection connection = (HttpURLConnection)url.openConnection();
1

12 Answers 12

150

There's a native and less intrusive alternative, which works only for your call.

URL url = new URL(“location address”);
URLConnection uc = url.openConnection();
String userpass = username + ":" + password;
String basicAuth = "Basic " + new String(Base64.getEncoder().encode(userpass.getBytes()));
uc.setRequestProperty ("Authorization", basicAuth);
InputStream in = uc.getInputStream();
Sign up to request clarification or add additional context in comments.

6 Comments

The Base64 class can be provided by Apache Commons Codec.
It's 'native' on Grails and many other Java frameworks because them all use Apache Commons Libs.
Does not work in general unless you .trim() the result, or call a method variant that does not produce chunked output. javax.xml.bind.DatatypeConverter seems safer.
Shouldn't you be storing the password in a char[]? stackoverflow.com/questions/8881291/…
The native Base64 encoding was flawed until Java 8 so it might explain why it wasn't working on some configurations before.
|
142

You can set the default authenticator for http requests like this:

Authenticator.setDefault (new Authenticator() {
    protected PasswordAuthentication getPasswordAuthentication() {
        return new PasswordAuthentication ("username", "password".toCharArray());
    }
});

Also, if you require more flexibility, you can check out the Apache HttpClient, which will give you more authentication options (as well as session support, etc.)

5 Comments

The above code works but is quite implicit as to whats going on. There's subclassing and method overriding going on there, dig into the docs for those classes if you care to know what's going on. The code here is more explicit javacodegeeks
Is it possible to set specific Authenticator per specific URL.openConnection() invocation rather than setting it globally?
@Yura: no. It's got to be global. You can, however, do evil things such as setting a global authenticator which pulls the credentials out of thread-local variables, and set the credentials per thread before making the HTTP connection.
You can do this: connection.setAuthenticator(...)
In response to @YuriyNakonechnyy... if you are using Java 9 or above then you can call HttpURLConnection.setAuthenticator(). Unfortunately on Java 8 and earlier, the Authenticator instance is a JVM-wide global variable. See: docs.oracle.com/javase/9/docs/api/java/net/…
81

You can also use the following, which does not require using external packages:

URL url = new URL(“location address”);
URLConnection uc = url.openConnection();

String userpass = username + ":" + password;
String basicAuth = "Basic " + javax.xml.bind.DatatypeConverter.printBase64Binary(userpass.getBytes());

uc.setRequestProperty ("Authorization", basicAuth);
InputStream in = uc.getInputStream();

1 Comment

Note that for Java9+ you'll probably have to --add-modules javax.xml.bind since they removed the package from the default classpath. And in Java11+ it's removed altogether, you need an external dependency again. Such is progress!
48

If you are using the normal login whilst entering the username and password between the protocol and the domain this is simpler. It also works with and without login.

Sample URL: http://user:[email protected]/url

URL url = new URL("http://user:[email protected]/url");
URLConnection urlConnection = url.openConnection();

if (url.getUserInfo() != null) {
    String basicAuth = "Basic " + new String(new Base64().encode(url.getUserInfo().getBytes()));
    urlConnection.setRequestProperty("Authorization", basicAuth);
}

InputStream inputStream = urlConnection.getInputStream();

Please note in the comment, from valerybodak, below how it is done in an Android development environment.

2 Comments

If your username/password contain special characters, I believe you would need to urlencode those. Then, in the snippet of code above, you would pass url.getUserInfo() thorugh URLDecoder.decode() first (@Peter Rader).
Thanks, but for android you should use Base64 as following: String basicAuth = "Basic " + Base64.encodeToString(url.getUserInfo().getBytes(), Base64.DEFAULT); httpConn.setRequestProperty("Authorization", basicAuth);
8

As I have came here looking for an Android-Java-Answer I am going to do a short summary:

  1. Use java.net.Authenticator as shown by James van Huis
  2. Use Apache Commons HTTP Client, as in this Answer
  3. Use basic java.net.URLConnection and set the Authentication-Header manually like shown here

If you want to use java.net.URLConnection with Basic Authentication in Android try this code:

URL url = new URL("http://www.example.com/resource");
URLConnection urlConnection = url.openConnection();
String header = "Basic " + new String(android.util.Base64.encode("user:pass".getBytes(), android.util.Base64.NO_WRAP));
urlConnection.addRequestProperty("Authorization", header);
// go on setting more request headers, reading the response, etc

Comments

7

Was able to set the auth using the HttpsURLConnection

           URL myUrl = new URL(httpsURL);
            HttpsURLConnection conn = (HttpsURLConnection)myUrl.openConnection();
            String userpass = username + ":" + password;
            String basicAuth = "Basic " + new String(Base64.getEncoder().encode(userpass.getBytes()));
            //httpsurlconnection
            conn.setRequestProperty("Authorization", basicAuth);

few of the changes fetched from this post. and Base64 is from java.util package.

Comments

6

Since Java 9, you can do this

URL url = new URL("http://www.example.com");
HttpURLConnection connection = (HttpURLConnection)url.openConnection();
connection.setAuthenticator(new Authenticator() {
    protected PasswordAuthentication getPasswordAuthentication() {
        return new PasswordAuthentication ("USER", "PASS".toCharArray());
    }
});

3 Comments

Haven't see setAuthenticator() method.
nor me.... I wish this were possible as the code is very tidy.
Works for me. Clean. I like it.
5

Be really careful with the "Base64().encode()"approach, my team and I got 400 Apache bad request issues because it adds a \r\n at the end of the string generated.

We found it sniffing packets thanks to Wireshark.

Here is our solution :

import org.apache.commons.codec.binary.Base64;

HttpGet getRequest = new HttpGet(endpoint);
getRequest.addHeader("Authorization", "Basic " + getBasicAuthenticationEncoding());

private String getBasicAuthenticationEncoding() {

        String userPassword = username + ":" + password;
        return new String(Base64.encodeBase64(userPassword.getBytes()));
    }

Hope it helps!

Comments

4

I'd like to provide an answer for the case that you do not have control over the code that opens the connection. Like I did when using the URLClassLoader to load a jar file from a password protected server.

The Authenticator solution would work but has the drawback that it first tries to reach the server without a password and only after the server asks for a password provides one. That's an unnecessary roundtrip if you already know the server would need a password.

public class MyStreamHandlerFactory implements URLStreamHandlerFactory {

    private final ServerInfo serverInfo;

    public MyStreamHandlerFactory(ServerInfo serverInfo) {
        this.serverInfo = serverInfo;
    }

    @Override
    public URLStreamHandler createURLStreamHandler(String protocol) {
        switch (protocol) {
            case "my":
                return new MyStreamHandler(serverInfo);
            default:
                return null;
        }
    }

}

public class MyStreamHandler extends URLStreamHandler {

    private final String encodedCredentials;

    public MyStreamHandler(ServerInfo serverInfo) {
        String strCredentials = serverInfo.getUsername() + ":" + serverInfo.getPassword();
        this.encodedCredentials = Base64.getEncoder().encodeToString(strCredentials.getBytes());
    }

    @Override
    protected URLConnection openConnection(URL url) throws IOException {
        String authority = url.getAuthority();
        String protocol = "http";
        URL directUrl = new URL(protocol, url.getHost(), url.getPort(), url.getFile());

        HttpURLConnection connection = (HttpURLConnection) directUrl.openConnection();
        connection.setRequestProperty("Authorization", "Basic " + encodedCredentials);

        return connection;
    }

}

This registers a new protocol my that is replaced by http when credentials are added. So when creating the new URLClassLoader just replace http with my and everything is fine. I know URLClassLoader provides a constructor that takes an URLStreamHandlerFactory but this factory is not used if the URL points to a jar file.

Comments

3

Use this code for basic authentication.

URL url = new URL(path);
String userPass = "username:password";
String basicAuth = "Basic " + Base64.encodeToString(userPass.getBytes(), Base64.DEFAULT);//or
//String basicAuth = "Basic " + new String(Base64.encode(userPass.getBytes(), Base64.No_WRAP));
HttpURLConnection urlConnection = (HttpURLConnection)url.openConnection();
urlConnection.setRequestProperty("Authorization", basicAuth);
urlConnection.connect();

Comments

1

i did that this way you need to do this just copy paste it be happy

    HttpURLConnection urlConnection;
    String url;
 //   String data = json;
    String result = null;
    try {
        String username ="[email protected]";
        String password = "12345678";

        String auth =new String(username + ":" + password);
        byte[] data1 = auth.getBytes(UTF_8);
        String base64 = Base64.encodeToString(data1, Base64.NO_WRAP);
        //Connect
        urlConnection = (HttpURLConnection) ((new URL(urlBasePath).openConnection()));
        urlConnection.setDoOutput(true);
        urlConnection.setRequestProperty("Content-Type", "application/json");
        urlConnection.setRequestProperty("Authorization", "Basic "+base64);
        urlConnection.setRequestProperty("Accept", "application/json");
        urlConnection.setRequestMethod("POST");
        urlConnection.setConnectTimeout(10000);
        urlConnection.connect();
        JSONObject obj = new JSONObject();

        obj.put("MobileNumber", "+97333746934");
        obj.put("EmailAddress", "[email protected]");
        obj.put("FirstName", "Danish");
        obj.put("LastName", "Hussain");
        obj.put("Country", "BH");
        obj.put("Language", "EN");
        String data = obj.toString();
        //Write
        OutputStream outputStream = urlConnection.getOutputStream();
        BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(outputStream, "UTF-8"));
        writer.write(data);
        writer.close();
        outputStream.close();
        int responseCode=urlConnection.getResponseCode();
        if (responseCode == HttpsURLConnection.HTTP_OK) {
            //Read
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(urlConnection.getInputStream(), "UTF-8"));

        String line = null;
        StringBuilder sb = new StringBuilder();

        while ((line = bufferedReader.readLine()) != null) {
            sb.append(line);
        }

        bufferedReader.close();
        result = sb.toString();

        }else {
        //    return new String("false : "+responseCode);
        new String("false : "+responseCode);
        }

    } catch (UnsupportedEncodingException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    } catch (JSONException e) {
        e.printStackTrace();
    }

Comments

0

ANDROD IMPLEMENTATION A complete method to request data/string response from web service requesting authorization with username and password

public static String getData(String uri, String userName, String userPassword) {
        BufferedReader reader = null;
        byte[] loginBytes = (userName + ":" + userPassword).getBytes();

        StringBuilder loginBuilder = new StringBuilder()
                .append("Basic ")
                .append(Base64.encodeToString(loginBytes, Base64.DEFAULT));

        try {
            URL url = new URL(uri);
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            connection.addRequestProperty("Authorization", loginBuilder.toString());

            StringBuilder sb = new StringBuilder();
            reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
            String line;
            while ((line = reader.readLine())!= null){
                sb.append(line);
                sb.append("\n");
            }

            return  sb.toString();

        } catch (Exception e) {
            e.printStackTrace();
            return null;
        } finally {
            if (null != reader){
                try {
                    reader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.