server session FEATURE option to store user data in a session
diff --git a/src/session.c b/src/session.c
index 49f0591..e2194d9 100644
--- a/src/session.c
+++ b/src/session.c
@@ -212,6 +212,28 @@
     return NULL;
 }
 
+API void
+nc_session_set_data(struct nc_session *session, void *data)
+{
+    if (!session) {
+        ERRARG;
+        return;
+    }
+
+    session->data = data;
+}
+
+API void *
+nc_session_get_data(const struct nc_session *session)
+{
+    if (!session) {
+        ERRARG;
+        return NULL;
+    }
+
+    return session->data;
+}
+
 NC_MSG_TYPE
 nc_send_msg(struct nc_session *session, struct lyd_node *op)
 {
diff --git a/src/session.h b/src/session.h
index 34ab0a0..1eb030a 100644
--- a/src/session.h
+++ b/src/session.h
@@ -157,6 +157,22 @@
 const char *nc_session_cpblt(const struct nc_session *session, const char *capab);
 
 /**
+ * @brief Assign arbitrary data to a session.
+ *
+ * @param[in] session Session to modify.
+ * @param[in] data Data to be stored in the session.
+ */
+void nc_session_set_data(struct nc_session *session, void *data);
+
+/**
+ * @brief Get the data assigned to a session.
+ *
+ * @param[in] session Session to get the data from.
+ * @return Session-specific data.
+ */
+void *nc_session_get_data(const struct nc_session *session);
+
+/**
  * @brief Free the NETCONF session object.
  *
  * @param[in] session Object to free.
diff --git a/src/session_p.h b/src/session_p.h
index 903fc23..90ece02 100644
--- a/src/session_p.h
+++ b/src/session_p.h
@@ -240,6 +240,7 @@
 
     /* other */
     struct ly_ctx *ctx;            /**< libyang context of the session */
+    void *data;                    /**< arbitrary user data */
     uint8_t flags;                 /**< various flags of the session - TODO combine with status and/or side */
 #define NC_SESSION_SHAREDCTX 0x01
 #define NC_SESSION_CALLHOME 0x02
@@ -251,7 +252,6 @@
     struct nc_msg_cont *notifs;    /**< queue for notifications received instead of RPC reply */
 
     /* server side only data */
-    void *ti_opts;
     time_t last_rpc;               /**< time the last RPC was received on this session */
 #ifdef NC_ENABLED_SSH
     /* SSH session authenticated */
diff --git a/src/session_server.c b/src/session_server.c
index 7f7ce65..c4db176 100644
--- a/src/session_server.c
+++ b/src/session_server.c
@@ -1104,7 +1104,7 @@
     }
     pthread_mutex_init((*session)->ti_lock, NULL);
 
-    (*session)->ti_opts = server_opts.endpts[idx].ti_opts;
+    (*session)->data = server_opts.endpts[idx].ti_opts;
 
     /* sock gets assigned to session or closed */
 #ifdef NC_ENABLED_SSH
@@ -1130,6 +1130,8 @@
         goto fail;
     }
 
+    (*session)->data = NULL;
+
     /* WRITE UNLOCK */
     pthread_rwlock_unlock(&server_opts.endpt_array_lock);
 
@@ -1203,9 +1205,9 @@
         /* OPTS LOCK */
         pthread_mutex_lock(&ssh_ch_opts_lock);
 
-        (*session)->ti_opts = &ssh_ch_opts;
+        (*session)->data = &ssh_ch_opts;
         ret = nc_accept_ssh_session(*session, sock);
-        (*session)->ti_opts = NULL;
+        (*session)->data = NULL;
 
         /* OPTS UNLOCK */
         pthread_mutex_unlock(&ssh_ch_opts_lock);
@@ -1220,9 +1222,9 @@
         /* OPTS LOCK */
         pthread_mutex_lock(&tls_ch_opts_lock);
 
-        (*session)->ti_opts = &tls_ch_opts;
+        (*session)->data = &tls_ch_opts;
         ret = nc_accept_tls_session(*session, sock);
-        (*session)->ti_opts = NULL;
+        (*session)->data = NULL;
 
         /* OPTS UNLOCK */
         pthread_mutex_unlock(&tls_ch_opts_lock);
diff --git a/src/session_server_ssh.c b/src/session_server_ssh.c
index 8c5760a..23d5767 100644
--- a/src/session_server_ssh.c
+++ b/src/session_server_ssh.c
@@ -607,7 +607,7 @@
         return;
 
     } else if (signature_state == SSH_PUBLICKEY_STATE_NONE) {
-        if ((username = auth_pubkey_compare_key(session->ti_opts, ssh_message_auth_pubkey(msg))) == NULL) {
+        if ((username = auth_pubkey_compare_key(session->data, ssh_message_auth_pubkey(msg))) == NULL) {
             VRB("User \"%s\" tried to use an unknown (unauthorized) public key.", session->username);
 
         } else if (strcmp(session->username, username)) {
@@ -846,7 +846,7 @@
             return 0;
         }
 
-        if (session->ssh_auth_attempts >= ((struct nc_server_ssh_opts *)session->ti_opts)->auth_attempts) {
+        if (session->ssh_auth_attempts >= ((struct nc_server_ssh_opts *)session->data)->auth_attempts) {
             /* too many failed attempts */
             ssh_message_reply_default(msg);
             return 0;
@@ -1073,7 +1073,7 @@
     struct nc_server_ssh_opts *opts;
     int libssh_auth_methods = 0, elapsed_usec = 0, ret;
 
-    opts = session->ti_opts;
+    opts = session->data;
 
     /* other transport-specific data */
     session->ti_type = NC_TI_LIBSSH;
diff --git a/src/session_server_tls.c b/src/session_server_tls.c
index b0b9c04..62b789f 100644
--- a/src/session_server_tls.c
+++ b/src/session_server_tls.c
@@ -465,7 +465,7 @@
         return 0;
     }
 
-    opts = session->ti_opts;
+    opts = session->data;
 
     /* get the last certificate, that is the peer (client) certificate */
     if (!session->tls_cert) {
@@ -1491,7 +1491,7 @@
     struct nc_server_tls_opts *opts;
     int ret;
 
-    opts = session->ti_opts;
+    opts = session->data;
 
     session->ti_type = NC_TI_OPENSSL;
     session->ti.tls = SSL_new(opts->tls_ctx);