diff --git a/configure.ac b/configure.ac
index cc85701..733b3f4 100644
--- a/configure.ac
+++ b/configure.ac
@@ -335,6 +335,20 @@ fi
 AC_SUBST(ntlm_auth)
 AC_DEFINE_UNQUOTED(NTLM_AUTH, "$ntlm_auth", [Samba's 'winbind' daemon helper 'ntlm_auth' which can be used for NTLM single-sign-on])
 
+dnl **********************
+dnl *** GSSAPI support ***
+dnl **********************
+AC_PATH_PROG([KRB5_CONFIG], krb5-config, none, $PATH:/usr/kerberos/bin)
+if test "x$KRB5_CONFIG" != "xnone"; then
+    KRB5_LIBS="`${KRB5_CONFIG} --libs gssapi`"
+    KRB5_CFLAGS="`${KRB5_CONFIG} --cflags gssapi`"
+    AC_SUBST(KRB5_CFLAGS)
+    AC_SUBST(KRB5_LIBS)
+    if test "$KRB5_CONFIG" != none; then
+        AC_DEFINE(HAVE_GSSAPI, 1, [Whether or not can gssapi libs are available])
+    fi
+fi
+
 dnl ****************************************************
 dnl *** Warnings to show if using GCC                ***
 dnl *** (do this last so -Werror won't mess up tests ***
diff --git a/libsoup/Makefile.am b/libsoup/Makefile.am
index d2e2cde..c28c955 100644
--- a/libsoup/Makefile.am
+++ b/libsoup/Makefile.am
@@ -18,7 +18,8 @@ INCLUDES = 				\
 	$(GLIB_CFLAGS)			\
 	$(XML_CFLAGS)			\
 	$(SQLITE_CFLAGS)		\
-	$(GNOME_KEYRING_CFLAGS)
+	$(GNOME_KEYRING_CFLAGS)		\
+	$(KRB5_CFLAGS)
 
 libsoupincludedir = $(includedir)/libsoup-2.4/libsoup
 
@@ -92,6 +93,7 @@ libsoup_2_4_la_LIBADD =			\
 	$(XML_LIBS)			\
 	$(SQLITE_LIBS)			\
 	-lz				\
+	$(KRB5_LIBS)			\
 	$(LIBWS2_32)
 
 libsoup_2_4_la_SOURCES =		\
@@ -103,6 +105,8 @@ libsoup_2_4_la_SOURCES =		\
 	soup-auth-digest.c		\
 	soup-auth-ntlm.h		\
 	soup-auth-ntlm.c		\
+	soup-auth-negotiate.h		\
+	soup-auth-negotiate.c		\
 	soup-auth-domain.c		\
 	soup-auth-domain-basic.c	\
 	soup-auth-domain-digest.c	\
diff --git a/libsoup/libsoup-2.4.sym b/libsoup/libsoup-2.4.sym
index 22af160..a05bd50 100644
--- a/libsoup/libsoup-2.4.sym
+++ b/libsoup/libsoup-2.4.sym
@@ -56,6 +56,7 @@ soup_auth_is_for_proxy
 soup_auth_is_ready
 soup_auth_manager_get_type
 soup_auth_manager_use_auth
+soup_auth_negotiate_get_type
 soup_auth_new
 soup_auth_ntlm_get_type
 soup_auth_save_password
diff --git a/libsoup/soup-auth-negotiate.c b/libsoup/soup-auth-negotiate.c
new file mode 100644
index 0000000..6801eac
--- /dev/null
+++ b/libsoup/soup-auth-negotiate.c
@@ -0,0 +1,550 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * soup-auth-negotiate.c: HTTP Negotiate Authentication helper
+ *
+ * Copyright (C) 2009,2013 Guido Guenther <agx@sigxcpu.org>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+
+#include <gssapi/gssapi.h>
+#include <gssapi/gssapi_krb5.h>
+
+#include "soup-auth-negotiate.h"
+#include "soup-headers.h"
+#include "soup-message.h"
+#include "soup-message-private.h"
+#include "soup-misc.h"
+#include "soup-uri.h"
+
+typedef enum {
+	SOUP_NEGOTIATE_NEW,
+	SOUP_NEGOTIATE_RECEIVED_CHALLENGE, /* received intial negotiate header */
+	SOUP_NEGOTIATE_SENT_RESPONSE,      /* sent response to server */
+	SOUP_NEGOTIATE_FAILED
+} SoupNegotiateState;
+
+typedef struct {
+	SoupNegotiateState state;
+
+	gss_ctx_id_t context;
+	gss_name_t   server_name;
+
+	char *response_header;
+} SoupNegotiateConnectionState;
+
+static gboolean soup_gss_build_response (SoupNegotiateConnectionState *conn,
+					 SoupAuth *auth, GError **err);
+static gchar** parse_trusted_uris (void);
+static gboolean check_auth_trusted_uri (SoupAuthNegotiate *negotiate,
+					SoupMessage *msg);
+static gint soup_gss_client_step (SoupNegotiateConnectionState *conn,
+				  const char *challenge, GError **err);
+
+typedef struct {
+	char *username;
+	gchar **trusted_uris;  /* Uris we try negotiate against */
+} SoupAuthNegotiatePrivate;
+#define SOUP_AUTH_NEGOTIATE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), SOUP_TYPE_AUTH_NEGOTIATE, SoupAuthNegotiatePrivate))
+
+G_DEFINE_TYPE (SoupAuthNegotiate, soup_auth_negotiate, SOUP_TYPE_CONNECTION_AUTH)
+
+#define AUTH_GSS_ERROR      -1
+#define AUTH_GSS_COMPLETE    1
+#define AUTH_GSS_CONTINUE    0
+
+static void
+soup_auth_negotiate_init (SoupAuthNegotiate *negotiate)
+{
+	SoupAuthNegotiatePrivate *priv = \
+		SOUP_AUTH_NEGOTIATE_GET_PRIVATE (negotiate);
+
+	priv->trusted_uris = parse_trusted_uris();
+}
+
+static void
+soup_auth_negotiate_finalize (GObject *object)
+{
+	SoupAuthNegotiatePrivate *priv = SOUP_AUTH_NEGOTIATE_GET_PRIVATE (object);
+
+	g_free (priv->username);
+
+	g_strfreev (priv->trusted_uris);
+
+	G_OBJECT_CLASS (soup_auth_negotiate_parent_class)->finalize (object);
+}
+
+static gpointer
+soup_auth_negotiate_create_connection_state (SoupConnectionAuth *auth)
+{
+	return g_slice_new0 (SoupNegotiateConnectionState);
+}
+
+static void
+soup_auth_negotiate_free_connection_state (SoupConnectionAuth *auth,
+					   gpointer state)
+{
+	SoupNegotiateConnectionState *conn = state;
+	OM_uint32 min_stat;
+
+	gss_release_name (&min_stat, &conn->server_name);
+	g_free (conn->response_header);
+}
+
+
+static gboolean
+soup_auth_negotiate_update_connection (SoupConnectionAuth *auth, SoupMessage *msg,
+				       const char *header, gpointer state)
+{
+	SoupAuthNegotiatePrivate *priv =
+		SOUP_AUTH_NEGOTIATE_GET_PRIVATE (auth);
+	SoupNegotiateConnectionState *conn = state;
+	GError *err = NULL;
+
+	if (conn->state > SOUP_NEGOTIATE_RECEIVED_CHALLENGE) {
+		/* We already authenticated, but then got another 401.
+		 * That means "permission denied", so don't try to
+		 * authenticate again.
+		 */
+		conn->state = SOUP_NEGOTIATE_FAILED;
+
+		/* Make sure we don't claim to be authenticated */
+		g_free (priv->username);
+		priv->username = NULL;
+
+		return FALSE;
+	}
+
+	/* Found negotiate header, start negotiate */
+	if (strcmp (header, "Negotiate") == 0) {
+		conn->state = SOUP_NEGOTIATE_RECEIVED_CHALLENGE;
+		if (soup_gss_build_response (conn, SOUP_AUTH (auth), &err))
+			return TRUE;
+		else {
+			/* FIXME: report further upward? */
+			g_warning("gssapi step failed: %s", err->message);
+
+		}
+	}
+	g_error_free(err);
+	return FALSE;
+}
+
+static GSList *
+soup_auth_negotiate_get_protection_space (SoupAuth *auth, SoupURI *source_uri)
+{
+	char *space, *p;
+
+	space = g_strdup (source_uri->path);
+
+	/* Strip query and filename component */
+	p = strrchr (space, '/');
+	if (p && p != space && p[1])
+		*p = '\0';
+
+	return g_slist_prepend (NULL, space);
+}
+
+static void
+soup_auth_negotiate_authenticate (SoupAuth *auth, const char *username,
+				  const char *password)
+{
+	SoupAuthNegotiatePrivate *priv = SOUP_AUTH_NEGOTIATE_GET_PRIVATE (auth);
+
+	g_return_if_fail (username != NULL);
+	priv->username = g_strdup (username);
+}
+
+static gboolean
+soup_auth_negotiate_is_authenticated (SoupAuth *auth)
+{
+	return SOUP_AUTH_NEGOTIATE_GET_PRIVATE (auth)->username != NULL;
+}
+
+static gboolean
+soup_auth_negotiate_is_ready (SoupAuth *auth,
+			      SoupMessage *msg)
+{
+	SoupAuthNegotiate* negotiate = SOUP_AUTH_NEGOTIATE(auth);
+	return check_auth_trusted_uri(negotiate, msg);
+}
+
+
+static void
+check_server_response(SoupMessage *msg, gpointer state)
+{
+	gchar **parts, *p;
+	gint ret;
+	const char *auth_headers;
+	SoupNegotiateConnectionState *conn = state;
+	GError *err = NULL;
+
+	if (msg->status_code == SOUP_STATUS_UNAUTHORIZED)
+		return;
+
+	/* FIXME: need to check for proxy-auth too */
+	auth_headers = soup_message_headers_get_list (msg->response_headers,
+						      "WWW-Authenticate");
+	parts = g_strsplit(auth_headers, " ", 0);
+	if (g_strv_length(parts) != 2) {
+		g_warning("Failed to parse auth header %s", auth_headers);
+		conn->state = SOUP_NEGOTIATE_FAILED;
+		goto out;
+	}
+
+	p = parts[1];
+	ret = soup_gss_client_step (conn, p, &err);
+
+	if (ret != AUTH_GSS_COMPLETE) {
+		g_warning("%s", err->message);
+		conn->state = SOUP_NEGOTIATE_FAILED;
+	}
+ out:
+	g_error_free(err);
+	g_strfreev(parts);
+}
+
+
+static void
+remove_server_response_handler(SoupMessage *msg, gpointer state)
+{
+	g_signal_handlers_disconnect_matched (msg,
+			      G_SIGNAL_MATCH_DATA | G_SIGNAL_MATCH_FUNC,
+			      0, 0, NULL,
+			      G_CALLBACK(check_server_response),
+			      state);
+}
+
+
+static char *
+soup_auth_negotiate_get_connection_authorization (SoupConnectionAuth *auth,
+						  SoupMessage *msg,
+						  gpointer state)
+{
+	SoupNegotiateConnectionState *conn = state;
+	char *header = NULL;
+
+	if (conn->state == SOUP_NEGOTIATE_RECEIVED_CHALLENGE) {
+		header = conn->response_header;
+		conn->response_header = NULL;
+		conn->state = SOUP_NEGOTIATE_SENT_RESPONSE;
+	}
+
+
+	g_signal_connect(msg,
+			 "finished",
+			 G_CALLBACK (remove_server_response_handler),
+			 conn);
+
+	/* Wait for the 2xx response to verify server response */
+	g_signal_connect (msg,
+			  "got_headers",
+			  G_CALLBACK (check_server_response),
+			  conn);
+
+	return header;
+}
+
+static gboolean
+soup_auth_negotiate_is_connection_ready (SoupConnectionAuth *auth,
+					 SoupMessage        *msg,
+					 gpointer            state)
+{
+	SoupNegotiateConnectionState *conn = state;
+
+	return conn->state != SOUP_NEGOTIATE_FAILED;
+}
+
+static void
+soup_auth_negotiate_class_init (SoupAuthNegotiateClass *auth_negotiate_class)
+{
+	SoupAuthClass *auth_class = SOUP_AUTH_CLASS (auth_negotiate_class);
+	SoupConnectionAuthClass *connauth_class =
+			SOUP_CONNECTION_AUTH_CLASS (auth_negotiate_class);
+	GObjectClass *object_class = G_OBJECT_CLASS (auth_negotiate_class);
+
+	g_type_class_add_private (auth_negotiate_class, sizeof (SoupAuthNegotiatePrivate));
+
+	auth_class->scheme_name = "Negotiate";
+	auth_class->strength = 7;
+
+	auth_class->get_protection_space = soup_auth_negotiate_get_protection_space;
+	auth_class->authenticate = soup_auth_negotiate_authenticate;
+	auth_class->is_authenticated = soup_auth_negotiate_is_authenticated;
+	auth_class->is_ready = soup_auth_negotiate_is_ready;
+
+	connauth_class->create_connection_state = soup_auth_negotiate_create_connection_state;
+	connauth_class->free_connection_state = soup_auth_negotiate_free_connection_state;
+	connauth_class->update_connection = soup_auth_negotiate_update_connection;
+	connauth_class->get_connection_authorization = soup_auth_negotiate_get_connection_authorization;
+	connauth_class->is_connection_ready = soup_auth_negotiate_is_connection_ready;
+
+	object_class->finalize = soup_auth_negotiate_finalize;
+}
+
+/*
+ * GSSAPI functions
+ */
+
+static void
+soup_negotiate_error (OM_uint32 err_maj, OM_uint32 err_min, GError **err)
+{
+	OM_uint32 maj_stat, min_stat, msg_ctx = 0;
+	gss_buffer_desc status;
+	char *buf_maj = NULL, *buf_min = NULL;
+
+	do {
+		maj_stat = gss_display_status (&min_stat,
+					       err_maj,
+					       GSS_C_GSS_CODE,
+					       GSS_C_NO_OID,
+					       &msg_ctx,
+					       &status);
+		if (GSS_ERROR (maj_stat))
+			break;
+
+		buf_maj = g_strdup ((char*) status.value);
+		gss_release_buffer (&min_stat, &status);
+
+		maj_stat = gss_display_status (&min_stat,
+					       err_min,
+					       GSS_C_MECH_CODE,
+					       GSS_C_NULL_OID,
+					       &msg_ctx,
+					       &status);
+		if (!GSS_ERROR (maj_stat)) {
+			buf_min = g_strdup ((char*) status.value);
+			gss_release_buffer (&min_stat, &status);
+		}
+
+		if (err && *err == NULL) {
+			g_set_error(err,
+				    SOUP_HTTP_ERROR,
+				    SOUP_STATUS_GSSAPI_FAILED,
+				    "%s %s",
+				    buf_maj,
+				    buf_min ? buf_min : "");
+		}
+		g_free (buf_maj);
+		g_free (buf_min);
+		buf_min = buf_maj = NULL;
+	} while (!GSS_ERROR (maj_stat) && msg_ctx != 0);
+}
+
+static int
+soup_gss_client_init (SoupNegotiateConnectionState *conn, const char *host, GError **err)
+{
+	OM_uint32 maj_stat, min_stat;
+	char *service = NULL;
+	gss_buffer_desc token = GSS_C_EMPTY_BUFFER;
+	gboolean ret = FALSE;
+	gchar *h;
+
+	conn->server_name = GSS_C_NO_NAME;
+	conn->context = GSS_C_NO_CONTEXT;
+
+	h = g_ascii_strdown (host, -1);
+	service = g_strconcat ("HTTP/", h, NULL);
+	token.length = strlen (service);
+	token.value = (char *)service;
+
+	maj_stat = gss_import_name (&min_stat,
+				    &token,
+				    (gss_OID) GSS_KRB5_NT_PRINCIPAL_NAME,
+				    &conn->server_name);
+
+	if (GSS_ERROR (maj_stat)) {
+		soup_negotiate_error (maj_stat, min_stat, err);
+		ret = FALSE;
+		goto out;
+	}
+
+	ret = TRUE;
+out:
+	g_free (h);
+	g_free (service);
+	return ret;
+}
+
+static int
+soup_gss_client_step (SoupNegotiateConnectionState *conn, const char *challenge, GError **err)
+{
+	OM_uint32 maj_stat, min_stat;
+	gss_buffer_desc in = GSS_C_EMPTY_BUFFER;
+	gss_buffer_desc out = GSS_C_EMPTY_BUFFER;
+	int ret = AUTH_GSS_CONTINUE;
+
+	g_clear_pointer (&conn->response_header, g_free);
+
+	if (challenge && *challenge) {
+		size_t len;
+		in.value = g_base64_decode (challenge, &len);
+		in.length = len;
+	}
+
+	maj_stat = gss_init_sec_context (&min_stat,
+					 GSS_C_NO_CREDENTIAL,
+					 &conn->context,
+					 conn->server_name,
+					 GSS_C_NO_OID,
+					 GSS_C_MUTUAL_FLAG,
+					 GSS_C_INDEFINITE,
+					 GSS_C_NO_CHANNEL_BINDINGS,
+					 &in,
+					 NULL,
+					 &out,
+					 NULL,
+					 NULL);
+
+	if ((maj_stat != GSS_S_COMPLETE) && (maj_stat != GSS_S_CONTINUE_NEEDED)) {
+		soup_negotiate_error (maj_stat, min_stat, err);
+		ret = AUTH_GSS_ERROR;
+		goto out;
+	}
+
+	ret = (maj_stat == GSS_S_COMPLETE) ? AUTH_GSS_COMPLETE : AUTH_GSS_CONTINUE;
+	if (out.length) {
+		char *response = g_base64_encode ((const unsigned char *)out.value, out.length);
+		conn->response_header = g_strconcat ("Negotiate ", response, NULL);
+		g_free (response);
+		maj_stat = gss_release_buffer (&min_stat, &out);
+	}
+
+out:
+	if (out.value)
+		gss_release_buffer (&min_stat, &out);
+	if (in.value)
+		g_free (in.value);
+	return ret;
+}
+
+static gboolean
+soup_gss_build_response (SoupNegotiateConnectionState *conn, SoupAuth *auth, GError **err)
+{
+	if (!soup_gss_client_init (conn, soup_auth_get_host (SOUP_AUTH (auth)), err))
+		return FALSE;
+
+	if (soup_gss_client_step (conn, "", err) != AUTH_GSS_CONTINUE)
+		return FALSE;
+
+	return TRUE;
+}
+
+/* Parses a comma separated liste of URIS from the environment. This needs to be
+ * extended later similar to proxy resolution */
+static gchar**
+parse_trusted_uris(void)
+{
+	gchar **uris = NULL;
+	const gchar *env;
+
+	env = g_getenv("SOUP_AUTH_TRUSTED_URIS");
+	if (env)
+		uris = g_strsplit (env, ",", -1);
+	return uris;
+}
+
+
+/* check if scheme://host:port from msg matches the trusted uri */
+static gboolean
+match_base_uri (SoupMessage *msg, const gchar *trusted)
+{
+	SoupURI *uri;
+	gboolean ret = FALSE;
+
+	/* params of the trusted uri */
+	gchar **t_s_hp = NULL, **t_h_p = NULL;
+	const gchar *t_h = NULL;
+	gint t_h_len;
+
+	/* params of the msg's uri */
+	const gchar  *h = NULL;
+	gint port;
+	gint h_len;
+
+	uri = soup_message_get_uri (msg);
+	/* split trusted uri into scheme and host/port */
+	if (strstr (trusted, "://")) {
+		t_s_hp = g_strsplit (trusted, "://", -1);
+
+		/* The scheme has to match exactly */
+		if (g_ascii_strcasecmp (t_s_hp[0],
+                                  soup_uri_get_scheme(uri))) {
+			goto out;
+		}
+		if (strlen(t_s_hp[1]) == 0) {
+			/* scheme only, we're done */
+			ret = TRUE;
+			goto out;
+		} else
+			t_h = t_s_hp[1];
+	} else {
+		t_h = trusted;
+	}
+
+	t_h_p = g_strsplit (t_h, ":", 2);
+	/* If we got a port in the trusted uri it has to match exactly */
+	if (g_strv_length(t_h_p) > 1) {
+		port = g_ascii_strtoll (t_h_p[1], NULL, 10);
+		if (port != soup_uri_get_port(uri)) {
+			goto out;
+		}
+	}
+
+	t_h = t_h_p[0];
+	h = soup_uri_get_host(uri);
+	if (g_str_has_suffix (h, t_h)) {
+	    /* if the msg host ends with host from the trusted uri, then make
+	     * sure it is either an exact match, or prefixed with a dot. We
+	     * don't want to match "foobar.com" to match "bar.com" */
+		if (g_ascii_strcasecmp (h, t_h) == 0) {
+			ret = TRUE;
+			goto out;
+		} else {
+			/* we don't want to example.com to match fooexample.com
+                         * */
+			t_h_len = strlen(t_h);
+			h_len = strlen(soup_uri_get_host(uri));
+			if (h[h_len-t_h_len-1] == '.') {
+				ret = TRUE;
+			}
+		}
+	}
+out:
+	g_strfreev (t_s_hp);
+	g_strfreev (t_h_p);
+	return ret;
+}
+
+
+static gboolean
+check_auth_trusted_uri (SoupAuthNegotiate *negotiate, SoupMessage *msg)
+{
+	SoupAuthNegotiatePrivate *priv = \
+		SOUP_AUTH_NEGOTIATE_GET_PRIVATE (negotiate);
+	int i;
+
+	g_return_val_if_fail (negotiate != NULL, FALSE);
+	g_return_val_if_fail (priv != NULL, FALSE);
+	g_return_val_if_fail (msg != NULL, FALSE);
+
+	/* We only use the uri list for negotiate auth for now */
+	if (g_ascii_strcasecmp (soup_auth_get_scheme_name(SOUP_AUTH(negotiate)),
+				"negotiate"))
+		return TRUE;
+
+	if (!priv->trusted_uris) {
+		return FALSE;
+	}
+
+	for (i=0; i < g_strv_length(priv->trusted_uris); i++) {
+		if (match_base_uri(msg, priv->trusted_uris[i]))
+			g_warning("matched");
+			return TRUE;
+	}
+	return FALSE;
+}
diff --git a/libsoup/soup-auth-negotiate.h b/libsoup/soup-auth-negotiate.h
new file mode 100644
index 0000000..dbdfc3c
--- /dev/null
+++ b/libsoup/soup-auth-negotiate.h
@@ -0,0 +1,27 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2010 Guido Guenther <agx@sigxcpu.org>
+ */
+
+#ifndef SOUP_AUTH_NEGOTIATE_H
+#define SOUP_AUTH_NEGOTIATE_H 1
+
+#include "soup-connection-auth.h"
+
+#define SOUP_AUTH_NEGOTIATE(object)         (G_TYPE_CHECK_INSTANCE_CAST ((object), SOUP_TYPE_AUTH_NEGOTIATE, SoupAuthNegotiate))
+#define SOUP_AUTH_NEGOTIATE_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), SOUP_TYPE_AUTH_NEGOTIATE, SoupAuthNegotiateClass))
+#define SOUP_IS_AUTH_NEGOTIATE(object)      (G_TYPE_CHECK_INSTANCE_TYPE ((object), SOUP_TYPE_AUTH_NEGOTIATE))
+#define SOUP_IS_AUTH_NEGOTIATE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SOUP_TYPE_AUTH_NEGOTIATE))
+#define SOUP_AUTH_NEGOTIATE_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), SOUP_TYPE_AUTH_NEGOTIATE, SoupAuthNegotiateClass))
+
+typedef struct {
+	SoupConnectionAuth parent;
+
+} SoupAuthNegotiate;
+
+typedef struct {
+	SoupConnectionAuthClass parent_class;
+
+} SoupAuthNegotiateClass;
+
+#endif /* SOUP_AUTH_NEGOTIATE_H */
diff --git a/libsoup/soup-auth.h b/libsoup/soup-auth.h
index 824857e..8db2ccc 100644
--- a/libsoup/soup-auth.h
+++ b/libsoup/soup-auth.h
@@ -99,6 +99,8 @@ GType soup_auth_basic_get_type  (void);
 GType soup_auth_digest_get_type (void);
 #define SOUP_TYPE_AUTH_NTLM   (soup_auth_ntlm_get_type ())
 GType soup_auth_ntlm_get_type   (void);
+#define SOUP_TYPE_AUTH_NEGOTIATE  (soup_auth_negotiate_get_type ())
+GType soup_auth_negotiate_get_type   (void);
 
 /* Deprecated SoupPasswordManager-related APIs: all are now no-ops */
 SOUP_AVAILABLE_IN_2_28
diff --git a/libsoup/soup-status.h b/libsoup/soup-status.h
index 669c122..24074e6 100644
--- a/libsoup/soup-status.h
+++ b/libsoup/soup-status.h
@@ -34,6 +34,7 @@ typedef enum {
 	SOUP_STATUS_TRY_AGAIN,
 	SOUP_STATUS_TOO_MANY_REDIRECTS,
 	SOUP_STATUS_TLS_FAILED,
+	SOUP_STATUS_GSSAPI_FAILED,
 
 	/* HTTP Status Codes */
 	SOUP_STATUS_CONTINUE                        = 100,
diff --git a/tests/get.c b/tests/get.c
index 15d6903..01d9ddf 100644
--- a/tests/get.c
+++ b/tests/get.c
@@ -84,7 +84,7 @@ get_url (const char *url)
 static void
 usage (void)
 {
-	g_printerr ("Usage: get [-c CAfile] [-p proxy URL] [-h] [-d] URL\n");
+	g_printerr ("Usage: get [-c CAfile] [-p proxy URL] [-h] [-n] [-N] [-d] URL\n");
 	exit (1);
 }
 
@@ -93,12 +93,12 @@ main (int argc, char **argv)
 {
 	const char *cafile = NULL, *url;
 	SoupURI *proxy = NULL, *parsed;
-	gboolean synchronous = FALSE, ntlm = FALSE;
+	gboolean synchronous = FALSE, ntlm = FALSE, negotiate = FALSE;
 	int opt;
 
 	method = SOUP_METHOD_GET;
 
-	while ((opt = getopt (argc, argv, "c:dhnp:qs")) != -1) {
+	while ((opt = getopt (argc, argv, "c:dhnNp:qs")) != -1) {
 		switch (opt) {
 		case 'c':
 			cafile = optarg;
@@ -117,6 +117,10 @@ main (int argc, char **argv)
 			ntlm = TRUE;
 			break;
 
+		case 'N':
+			negotiate = TRUE;
+			break;
+
 		case 'p':
 			proxy = soup_uri_new (optarg);
 			if (!proxy) {
@@ -179,6 +183,11 @@ main (int argc, char **argv)
 	} else
 		soup_session_add_feature_by_type (session, SOUP_TYPE_PROXY_RESOLVER_DEFAULT);
 
+	if (negotiate) {
+		soup_session_add_feature_by_type(session,
+						 SOUP_TYPE_AUTH_NEGOTIATE);
+	}
+
 	if (!synchronous)
 		loop = g_main_loop_new (NULL, TRUE);
 
