diff --git a/datafiles/schema-delete.sql b/datafiles/schema-delete.sql
index 0f55000b483381b7b8073b2389c270aa70cfd6c7..1dda6d5b4d7a5c96e68c64effa8df6bb90a04152 100644
--- a/datafiles/schema-delete.sql
+++ b/datafiles/schema-delete.sql
@@ -5,6 +5,7 @@ DROP TABLE generic_backend_connections;
 DROP TABLE sub_connections;
 DROP TABLE service_connections;
 DROP TYPE directionality;
+DROP TYPE security_attribute;
 DROP TYPE parameter;
 DROP TYPE label;
 
diff --git a/datafiles/schema.sql b/datafiles/schema.sql
index 150aa836e46fe550e1152e7029e541194436080b..6239ff33aa5c90f56c6daebe0845e696e262ba5f 100644
--- a/datafiles/schema.sql
+++ b/datafiles/schema.sql
@@ -12,6 +12,11 @@ CREATE TYPE parameter AS (
     label_value     text
 );
 
+CREATE TYPE security_attribute AS (
+    attribute_type  text,
+    atribute_value  text
+);
+
 CREATE TYPE directionality AS ENUM ('Bidirectional', 'Unidirectional');
 
 
@@ -40,6 +45,7 @@ CREATE TABLE service_connections (
     directionality          directionality              NOT NULL,
     bandwidth               integer                     NOT NULL, -- mbps
     parameter               parameter[],
+    security_attributes     security_attribute[],
     connection_trace        text[]
 );
 
diff --git a/onsa b/onsa
index b181816a1d69ec1d77fc3aa42c123831fe778290..71feeb44536d0616eb63ac7c747cb59f76ea9d89 100755
--- a/onsa
+++ b/onsa
@@ -105,7 +105,7 @@ def doMain():
         global_id       = config.subOptions[options.GLOBAL_ID]      or defaults.get(options.GLOBAL_ID)
 
         # can only be specified on command line for now
-        security_attributes = config.subOptions[options.SECURITY_ATTRIBUTES]
+        security_attributes = [ nsa.SecurityAttribute(type_, value) for type_, value in config.subOptions[options.SECURITY_ATTRIBUTES] ]
 
         if topology_file and network:
             from opennsa.topology import gole
@@ -129,7 +129,7 @@ def doMain():
 
         log.msg("Requester URL: %s" % requester_url)
 
-        nsi_header = nsa.NSIHeader(client_nsa.urn(), provider_nsa.urn(), reply_to=provider_nsa.endpoint, session_security_attrs=security_attributes)
+        nsi_header = nsa.NSIHeader(client_nsa.urn(), provider_nsa.urn(), reply_to=provider_nsa.endpoint, security_attributes=security_attributes)
 
         # setup ssl context
         public_key          = config.subOptions[options.CERTIFICATE]        or defaults.get(options.CERTIFICATE)
diff --git a/opennsa/aggregator.py b/opennsa/aggregator.py
index 914cf33b64cb4bc2234a41e2e45793a4fa8f9b78..997deae771bb0fa94151fed00978a4e23883b02f 100644
--- a/opennsa/aggregator.py
+++ b/opennsa/aggregator.py
@@ -191,6 +191,11 @@ class Aggregator:
             log.msg('Rejecting reserve request without connection trace')
             raise error.ConnectionCreateError('This NSA (%s) requires a connection trace in the header to create a reservation.' % self.nsa_.urn() )
 
+        user_attrs  = [ sa for sa in header.security_attributes if sa.type_ == 'user'  ]
+        if not user_attrs:
+            log.msg('Rejecting reserve request without user security attribute')
+            raise error.ConnectionCreateError('This NSA (%s) requires a user security attribute in the header to create a reservation.' % self.nsa_.urn() )
+
         connection_id = self.conn_prefix + ''.join( [ random.choice(string.hexdigits[:16]) for _ in range(12) ] )
 
         sd = criteria.service_def
@@ -223,7 +228,8 @@ class Aggregator:
                             source_network=source_stp.network, source_port=source_stp.port, source_label=source_stp.label,
                             dest_network=dest_stp.network, dest_port=dest_stp.port, dest_label=dest_stp.label,
                             start_time=criteria.schedule.start_time, end_time=criteria.schedule.end_time,
-                            symmetrical=sd.symmetric, directionality=sd.directionality, bandwidth=sd.capacity, connection_trace=header.connection_trace)
+                            symmetrical=sd.symmetric, directionality=sd.directionality, bandwidth=sd.capacity,
+                            security_attributes=header.security_attributes, connection_trace=header.connection_trace)
         yield conn.save()
 
         # Here we should return / callback and spawn off the path creation
@@ -332,7 +338,7 @@ class Aggregator:
             else:
                 provider_urn = cnt.URN_OGF_PREFIX + self.route_vectors.getProvider( cnt.URN_OGF_PREFIX + link.network )
 
-            c_header = nsa.NSIHeader(self.nsa_.urn(), provider_urn, session_security_attrs=header.session_security_attrs, connection_trace=conn_trace)
+            c_header = nsa.NSIHeader(self.nsa_.urn(), provider_urn, security_attributes=header.security_attributes, connection_trace=conn_trace)
 
             # this has to be done more generic sometime
             sd = nsa.Point2PointService(nsa.STP(link.network, link.src_port, link.src_label),
@@ -392,7 +398,7 @@ class Aggregator:
             for (sc_id, provider_urn) in reserved_connections:
 
                 provider = self.getProvider(provider_urn)
-                t_header = nsa.NSIHeader(self.nsa_.urn(), provider_urn, session_security_attrs=header.session_security_attrs)
+                t_header = nsa.NSIHeader(self.nsa_.urn(), provider_urn, security_attributes=header.security_attributes)
 
                 d = provider.terminate(t_header, sc_id)
                 d.addCallbacks(
@@ -427,7 +433,7 @@ class Aggregator:
         for sc in sub_connections:
             # we assume a provider is available
             provider = self.getProvider(sc.provider_nsa)
-            req_header = nsa.NSIHeader(self.nsa_.urn(), sc.provider_nsa, session_security_attrs=header.session_security_attrs)
+            req_header = nsa.NSIHeader(self.nsa_.urn(), sc.provider_nsa, security_attributes=header.security_attributes)
             # we should probably mark as committing before sending message...
             d = provider.reserveCommit(req_header, sc.connection_id)
             defs.append(d)
@@ -465,7 +471,7 @@ class Aggregator:
         for sc in sub_connections:
             save_defs.append( state.reserveAbort(sc) )
             provider = self.getProvider(sc.provider_nsa)
-            header = nsa.NSIHeader(self.nsa_.urn(), sc.provider_nsa, session_security_attrs=header.session_security_attrs)
+            header = nsa.NSIHeader(self.nsa_.urn(), sc.provider_nsa, security_attributes=header.security_attributes)
             d = provider.reserveAbort(header, sc.connection_id)
             defs.append(d)
 
@@ -508,7 +514,7 @@ class Aggregator:
 
         for sc in sub_connections:
             provider = self.getProvider(sc.provider_nsa)
-            header = nsa.NSIHeader(self.nsa_.urn(), sc.provider_nsa, session_security_attrs=header.session_security_attrs)
+            header = nsa.NSIHeader(self.nsa_.urn(), sc.provider_nsa, security_attributes=header.security_attributes)
             d = provider.provision(header, sc.connection_id)
             defs.append(d)
 
@@ -547,7 +553,7 @@ class Aggregator:
 
         for sc in sub_connections:
             provider = self.getProvider(sc.provider_nsa)
-            header = nsa.NSIHeader(self.nsa_.urn(), sc.provider_nsa, session_security_attrs=header.session_security_attrs)
+            header = nsa.NSIHeader(self.nsa_.urn(), sc.provider_nsa, security_attributes=header.security_attributes)
             d = provider.release(header, sc.connection_id)
             defs.append(d)
 
@@ -584,7 +590,7 @@ class Aggregator:
         for sc in sub_connections:
             # we assume a provider is available
             provider = self.getProvider(sc.provider_nsa)
-            header = nsa.NSIHeader(self.nsa_.urn(), sc.provider_nsa, session_security_attrs=header.session_security_attrs)
+            header = nsa.NSIHeader(self.nsa_.urn(), sc.provider_nsa, security_attributes=header.security_attributes)
             d = provider.terminate(header, sc.connection_id)
             defs.append(d)
 
diff --git a/opennsa/cli/parser.py b/opennsa/cli/parser.py
index 2ff1b1b70e616fe8f5f57631827161aaab3642df..4bf69e2fdc372edb335fae580de21ba251581dde 100644
--- a/opennsa/cli/parser.py
+++ b/opennsa/cli/parser.py
@@ -108,14 +108,14 @@ class EndTimeOption(usage.Options):
 class SecurityAttributeOptions(usage.Options):
     optParameters = [ [ options.SECURITY_ATTRIBUTES, 'j', None, 'Security attributes (format attr1=value1,attr2=value2)'] ]
     def postOptions(self):
-        key_values = []
+        sats = []
         if self[options.SECURITY_ATTRIBUTES]:
             for kv_split in self[options.SECURITY_ATTRIBUTES].split(','):
                 if not '=' in kv_split:
                     raise usage.UsageError('No = in key-value attribute %s' % kv_split)
                 key, value = kv_split.split('=',1)
-                key_values.append( (key, [value]) )
-            self[options.SECURITY_ATTRIBUTES] = key_values
+                sats.append( (key, value) )
+            self[options.SECURITY_ATTRIBUTES] = sats
 
 class BandwidthOption(usage.Options):
     optParameters = [ [ options.BANDWIDTH, 'b', None, 'Bandwidth (Megabits)'] ]
diff --git a/opennsa/database.py b/opennsa/database.py
index 8a590f842f2070a0ffde528c1caee8f0857ff24f..3f0a7b615a4316c25e4d98a5b2f5f5f4b2380a98 100644
--- a/opennsa/database.py
+++ b/opennsa/database.py
@@ -31,11 +31,15 @@ LOG_SYSTEM = 'opennsa.Database'
 def adaptLabel(label):
     return AsIs("(%s, %s)::label" % (adapt(label.type_), adapt(label.labelValue())))
 
+def adaptSecuritAttribute(label):
+    return AsIs("(%s, %s)::security_attribute" % (adapt(label.type_), adapt(label.value)))
+
 def adaptDatetime(dt):
     return AsIs("%s" % adapt(dt.isoformat()))
 
 
 register_adapter(nsa.Label, adaptLabel)
+register_adapter(nsa.SecurityAttribute, adaptSecuritAttribute)
 register_adapter(datetime.datetime, adaptDatetime)
 
 
@@ -44,6 +48,11 @@ class LabelComposite(CompositeCaster):
         return nsa.Label(*values)
 
 
+class SecuritAttributeComposite(CompositeCaster):
+    def make(self, values):
+        return nsa.SecurityAttribute(*values)
+
+
 def castDatetime(value, cur):
     return parser.parse(value)
 
@@ -57,6 +66,7 @@ def setupDatabase(database, user, password=None):
     conn = psycopg2.connect(user=user, password=password, database=database)
     cur = conn.cursor()
     register_composite('label', cur, globally=True, factory=LabelComposite)
+    register_composite('security_attribute', cur, globally=True, factory=SecuritAttributeComposite)
 
     cur.execute("SELECT oid FROM pg_type WHERE typname = 'timestamptz';")
     timestamptz_oid = cur.fetchone()[0]
diff --git a/opennsa/nsa.py b/opennsa/nsa.py
index ce7cf175f3cb555fee7f5f146e253021729f3344..8de5e90c271b4c7b1a566ea2e3395d8f57ff1dd1 100644
--- a/opennsa/nsa.py
+++ b/opennsa/nsa.py
@@ -28,12 +28,12 @@ BIDIRECTIONAL   = 'Bidirectional'
 
 class NSIHeader(object):
 
-    def __init__(self, requester_nsa, provider_nsa, correlation_id=None, reply_to=None, session_security_attrs=None, connection_trace=None):
+    def __init__(self, requester_nsa, provider_nsa, correlation_id=None, reply_to=None, security_attributes=None, connection_trace=None):
         self.requester_nsa          = requester_nsa
         self.provider_nsa           = provider_nsa
         self.correlation_id         = correlation_id or self._createCorrelationId()
         self.reply_to               = reply_to
-        self.session_security_attrs = session_security_attrs
+        self.security_attributes    = security_attributes or []
         self.connection_trace       = connection_trace
 
     def _createCorrelationId(self):
@@ -44,7 +44,21 @@ class NSIHeader(object):
 
 
     def __repr__(self):
-        return '<NSIHeader: %s, %s, %s, %s, %s>' % (self.requester_nsa, self.provider_nsa, self.correlation_id, self.reply_to, self.session_security_attrs)
+        return '<NSIHeader: %s, %s, %s, %s, %s, %s>' % (self.requester_nsa, self.provider_nsa, self.correlation_id, self.reply_to, self.security_attributes, self.connection_trace)
+
+
+
+class SecurityAttribute(object):
+    # a better name would be AuthZAttribute, but we are keeping the NSI lingo
+
+    def __init__(self, type_, value):
+        assert type(type_) is str, 'SecurityAttribute type must be a string'
+        assert type(value) is str, 'SecurityAttribute value must be a string'
+        self.type_ = type_
+        self.value = value
+
+    def __repr__(self):
+        return '<SecurityAttribute: %s, %s>' % (self.type_, self.value)
 
 
 
diff --git a/opennsa/protocols/nsi2/helper.py b/opennsa/protocols/nsi2/helper.py
index a9e93c21049f7ce8da50ed658544f318dd38c5de..d04764e729fc349e2850eb655f5aafcc123cd082 100644
--- a/opennsa/protocols/nsi2/helper.py
+++ b/opennsa/protocols/nsi2/helper.py
@@ -39,26 +39,31 @@ LABEL_MAP = {
 
 
 
-def createProviderHeader(requester_nsa_urn, provider_nsa_urn, reply_to=None, correlation_id=None, session_security_attributes=None, connection_trace=None):
-    return _createHeader(requester_nsa_urn, provider_nsa_urn, reply_to, correlation_id, session_security_attributes, connection_trace, protocol_type=cnt.CS2_PROVIDER)
+def createProviderHeader(requester_nsa_urn, provider_nsa_urn, reply_to=None, correlation_id=None, security_attributes=None, connection_trace=None):
+    return _createHeader(requester_nsa_urn, provider_nsa_urn, reply_to, correlation_id, security_attributes, connection_trace, protocol_type=cnt.CS2_PROVIDER)
 
 
-def createRequesterHeader(requester_nsa_urn, provider_nsa_urn, reply_to=None, correlation_id=None, session_security_attributes=None, connection_trace=None):
-    return _createHeader(requester_nsa_urn, provider_nsa_urn, reply_to, correlation_id, session_security_attributes, connection_trace, protocol_type=cnt.CS2_REQUESTER)
+def createRequesterHeader(requester_nsa_urn, provider_nsa_urn, reply_to=None, correlation_id=None, security_attributes=None, connection_trace=None):
+    return _createHeader(requester_nsa_urn, provider_nsa_urn, reply_to, correlation_id, security_attributes, connection_trace, protocol_type=cnt.CS2_REQUESTER)
 
 
-def _createHeader(requester_nsa_urn, provider_nsa_urn, reply_to=None, correlation_id=None, session_security_attributes=None, connection_trace=None, protocol_type=None):
+def _createHeader(requester_nsa_urn, provider_nsa_urn, reply_to=None, correlation_id=None, security_attributes=None, connection_trace=None, protocol_type=None):
 
     if protocol_type is None:
         raise AssertionError('Requester or provider protocol type must be specified')
 
-    ssats = []
-    if session_security_attributes:
-        for at, avs in session_security_attributes:
-            at = nsiframework.AttributeType(at, None, None, avs)
-            ssats.append( nsiframework.SessionSecurityAttrType( [ at ] ) )
+    sat = []
+    if security_attributes:
+        # group by name to adhere to gns spec
+        grouped_sats = {}
+        for sa in security_attributes:
+            grouped_sats.setdefault(sa.type_, []).append(sa.value)
 
-    header = nsiframework.CommonHeaderType(protocol_type, correlation_id, requester_nsa_urn, provider_nsa_urn, reply_to, ssats, connection_trace)
+        for name, values in grouped_sats.items():
+            at = nsiframework.AttributeType(name, None, None, values )
+            sat.append( nsiframework.SessionSecurityAttrType( [ at ] ) )
+
+    header = nsiframework.CommonHeaderType(protocol_type, correlation_id, requester_nsa_urn, provider_nsa_urn, reply_to, sat, connection_trace)
     header_element = header.xml(nsiframework.nsiHeader)
     return header_element
 
@@ -134,7 +139,8 @@ def parseRequest(soap_data):
     if header.sessionSecurityAttr:
         for ssa in header.sessionSecurityAttr:
             for attr in ssa.Attributes:
-                security_attributes.append( (attr.Name, attr.AttributeValue) )
+                for av in attr.AttributeValue:
+                    security_attributes.append( nsa.SecurityAttribute(attr.Name, av) )
 
     #if header.protocolVersion not in [ cnt.CS2_REQUESTER, cnt.CS2_PROVIDER ]:
     #    raise ValueError('Invalid protocol "%s". Only %s supported' % (header.protocolVersion, cnt.CS2_SERVICE_TYPE))
@@ -147,7 +153,7 @@ def parseRequest(soap_data):
         body = [ nsiconnection.parseElement(b) for b in bodies ]
 
     nsi_header = nsa.NSIHeader(header.requesterNSA, header.providerNSA, header.correlationId, header.replyTo,
-                               session_security_attrs=security_attributes, connection_trace=header.connectionTrace)
+                               security_attributes=security_attributes, connection_trace=header.connectionTrace)
 
     return nsi_header, body
 
diff --git a/opennsa/protocols/nsi2/requesterclient.py b/opennsa/protocols/nsi2/requesterclient.py
index 44adaab7bea625783aefcfc5167f7df4200c60ae..00f2f0a6675e028fbda42516a9d49b46e0c997cb 100644
--- a/opennsa/protocols/nsi2/requesterclient.py
+++ b/opennsa/protocols/nsi2/requesterclient.py
@@ -51,7 +51,7 @@ class RequesterClient:
     def _createGenericRequestType(self, body_element_name, header, connection_id):
 
         header_element = helper.createProviderHeader(header.requester_nsa, header.provider_nsa, self.reply_to, header.correlation_id,
-                                                     header.session_security_attrs, header.connection_trace)
+                                                     header.security_attributes, header.connection_trace)
 
         body_element = nsiconnection.GenericRequestType(connection_id).xml(body_element_name)
 
@@ -100,7 +100,7 @@ class RequesterClient:
         # payload construction
 
         header_element = helper.createProviderHeader(header.requester_nsa, header.provider_nsa, self.reply_to, header.correlation_id,
-                                                     header.session_security_attrs, header.connection_trace)
+                                                     header.security_attributes, header.connection_trace)
 
         schedule = criteria.schedule
         sd = criteria.service_def
@@ -197,7 +197,7 @@ class RequesterClient:
         self._checkHeader(header)
 
         header_element = helper.createProviderHeader(header.requester_nsa, header.provider_nsa, reply_to=self.reply_to, correlation_id=header.correlation_id,
-                                                     session_security_attributes=header.session_security_attrs, connection_trace=header.connection_trace)
+                                                     security_attributes=header.security_attributes, connection_trace=header.connection_trace)
 
         query_type = nsiconnection.QueryType(connection_ids, global_reservation_ids)
         body_element = query_type.xml(nsiconnection.querySummary)
@@ -217,7 +217,7 @@ class RequesterClient:
 
         # don't need to check header here
         header_element = helper.createProviderHeader(header.requester_nsa, header.provider_nsa, reply_to=self.reply_to, correlation_id=header.correlation_id,
-                                                     session_security_attributes=header.session_security_attrs, connection_trace=header.connection_trace)
+                                                     security_attributes=header.security_attributes, connection_trace=header.connection_trace)
 
         query_type = nsiconnection.QueryType(connection_ids, global_reservation_ids)
         body_element = query_type.xml(nsiconnection.querySummarySync)
diff --git a/test/test_providers.py b/test/test_providers.py
index e73734d2a94b31c7094e1636704908e244866de9..827015a657a951460ff26ae637d777f92fa3bb5a 100644
--- a/test/test_providers.py
+++ b/test/test_providers.py
@@ -520,7 +520,8 @@ class AggregatorTest(GenericProviderTest, unittest.TestCase):
 
     requester_agent = nsa.NetworkServiceAgent('test-requester:nsa', 'dud_endpoint1')
     provider_agent  = nsa.NetworkServiceAgent(GenericProviderTest.base + ':nsa', 'dud_endpoint2')
-    header          = nsa.NSIHeader(requester_agent.urn(), provider_agent.urn(), connection_trace= [ requester_agent.urn() + ':1' ])
+    header          = nsa.NSIHeader(requester_agent.urn(), provider_agent.urn(), connection_trace= [ requester_agent.urn() + ':1' ],
+                                    security_attributes = [ nsa.SecurityAttribute('user', 'testuser') ] )
 
     def setUp(self):
 
@@ -579,7 +580,8 @@ class RemoteProviderTest(GenericProviderTest, unittest.TestCase):
 
     requester_agent = nsa.NetworkServiceAgent('test-requester:nsa', 'http://localhost:%i/NSI/services/RequesterService2' % REQUESTER_PORT)
     provider_agent  = nsa.NetworkServiceAgent(GenericProviderTest.base + ':nsa', 'http://localhost:%i/NSI/services/CS2' % PROVIDER_PORT)
-    header   = nsa.NSIHeader(requester_agent.urn(), provider_agent.urn(), reply_to=requester_agent.endpoint, connection_trace=requester_agent.urn() + ':1')
+    header   = nsa.NSIHeader(requester_agent.urn(), provider_agent.urn(), reply_to=requester_agent.endpoint, connection_trace=requester_agent.urn() + ':1',
+                             security_attributes = [ nsa.SecurityAttribute('user', 'testuser') ] )
 
     def setUp(self):
         from twisted.web import resource, server