expose AuthContext in C#
diff --git a/src/csharp/Grpc.Core/Internal/AuthContextSafeHandle.cs b/src/csharp/Grpc.Core/Internal/AuthContextSafeHandle.cs
new file mode 100644
index 0000000..59e33a0
--- /dev/null
+++ b/src/csharp/Grpc.Core/Internal/AuthContextSafeHandle.cs
@@ -0,0 +1,119 @@
+#region Copyright notice and license
+
+// Copyright 2017, Google Inc.
+// All rights reserved.
+// 
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+// 
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+// 
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Runtime.InteropServices;
+using System.Text;
+using Grpc.Core;
+using Grpc.Core.Utils;
+
+namespace Grpc.Core.Internal
+{
+    /// <summary>
+    /// grpc_auth_context
+    /// </summary>
+    internal class AuthContextSafeHandle : SafeHandleZeroIsInvalid
+    {
+        static readonly NativeMethods Native = NativeMethods.Get();
+
+        private AuthContextSafeHandle()
+        {
+        }
+
+        /// <summary>
+        /// Copies contents of the native auth context into a new <c>AuthContext</c> instance.
+        /// </summary>
+        public AuthContext ToAuthContext()
+        {
+            if (IsInvalid)
+            {
+                return new AuthContext(null, new Dictionary<string, List<AuthProperty>>());
+            }
+
+            var peerIdentityPropertyName = Marshal.PtrToStringAnsi(Native.grpcsharp_auth_context_peer_identity_property_name(this));
+
+            var propertiesDict = new Dictionary<string, List<AuthProperty>>();
+
+            var it = Native.grpcsharp_auth_context_property_iterator(this);
+            IntPtr authPropertyPtr = IntPtr.Zero;
+            while ((authPropertyPtr = Native.grpcsharp_auth_property_iterator_next(ref it)) != IntPtr.Zero)
+            {
+                var authProperty = PtrToAuthProperty(authPropertyPtr);
+
+                if (!propertiesDict.ContainsKey(authProperty.Name))
+                {
+                    propertiesDict[authProperty.Name] = new List<AuthProperty>();
+                }
+                propertiesDict[authProperty.Name].Add(authProperty);
+            }
+
+            return new AuthContext(peerIdentityPropertyName, propertiesDict);
+        }
+
+        protected override bool ReleaseHandle()
+        {
+            Native.grpcsharp_auth_context_release(handle);
+            return true;
+        }
+
+        private AuthProperty PtrToAuthProperty(IntPtr authPropertyPtr)
+        {
+            var nativeAuthProperty = (NativeAuthProperty) Marshal.PtrToStructure(authPropertyPtr, typeof(NativeAuthProperty));
+            var name = Marshal.PtrToStringAnsi(nativeAuthProperty.Name);
+            var valueBytes = new byte[(int) nativeAuthProperty.ValueLength];
+            Marshal.Copy(nativeAuthProperty.Value, valueBytes, 0, (int)nativeAuthProperty.ValueLength);
+            return AuthProperty.CreateUnsafe(name, valueBytes);
+        }
+
+        /// <summary>
+        /// grpc_auth_property
+        /// </summary>
+        internal struct NativeAuthProperty
+        {
+            public IntPtr Name;
+            public IntPtr Value;
+            public UIntPtr ValueLength;
+        }
+
+        /// <summary>
+        /// grpc_auth_property_iterator
+        /// </summary>
+        internal struct NativeAuthPropertyIterator
+        {
+            public IntPtr AuthContext;
+            public UIntPtr Index;
+            public IntPtr Name;
+        }
+    }
+}
diff --git a/src/csharp/Grpc.Core/Internal/BatchContextSafeHandle.cs b/src/csharp/Grpc.Core/Internal/BatchContextSafeHandle.cs
index efae149..6dee6d8 100644
--- a/src/csharp/Grpc.Core/Internal/BatchContextSafeHandle.cs
+++ b/src/csharp/Grpc.Core/Internal/BatchContextSafeHandle.cs
@@ -43,7 +43,6 @@
     /// </summary>
     internal class BatchContextSafeHandle : SafeHandleZeroIsInvalid
     {
-        static readonly Encoding EncodingUTF8 = System.Text.Encoding.UTF8;
         static readonly NativeMethods Native = NativeMethods.Get();
 
         private BatchContextSafeHandle()
@@ -75,7 +74,7 @@
         {
             UIntPtr detailsLength;
             IntPtr detailsPtr = Native.grpcsharp_batch_context_recv_status_on_client_details(this, out detailsLength);
-            string details = PtrToStringUtf8(detailsPtr, (int) detailsLength.ToUInt32());
+            string details = MarshalUtils.PtrToStringUTF8(detailsPtr, (int) detailsLength.ToUInt32());
             var status = new Status(Native.grpcsharp_batch_context_recv_status_on_client_status(this), details);
 
             IntPtr metadataArrayPtr = Native.grpcsharp_batch_context_recv_status_on_client_trailing_metadata(this);
@@ -108,12 +107,5 @@
             Native.grpcsharp_batch_context_destroy(handle);
             return true;
         }
-
-        string PtrToStringUtf8(IntPtr ptr, int len)
-        {
-            var bytes = new byte[len];
-            Marshal.Copy(ptr, bytes, 0, len);
-            return EncodingUTF8.GetString(bytes);
-        }
     }
 }
diff --git a/src/csharp/Grpc.Core/Internal/CallSafeHandle.cs b/src/csharp/Grpc.Core/Internal/CallSafeHandle.cs
index 710ca48..3c368fb 100644
--- a/src/csharp/Grpc.Core/Internal/CallSafeHandle.cs
+++ b/src/csharp/Grpc.Core/Internal/CallSafeHandle.cs
@@ -45,7 +45,6 @@
     internal class CallSafeHandle : SafeHandleZeroIsInvalid, INativeCall
     {
         public static readonly CallSafeHandle NullInstance = new CallSafeHandle();
-        static readonly Encoding EncodingUTF8 = System.Text.Encoding.UTF8;
         static readonly NativeMethods Native = NativeMethods.Get();
 
         const uint GRPC_WRITE_BUFFER_HINT = 1;
@@ -140,7 +139,7 @@
                 var ctx = BatchContextSafeHandle.Create();
                 var optionalPayloadLength = optionalPayload != null ? new UIntPtr((ulong)optionalPayload.Length) : UIntPtr.Zero;
                 completionQueue.CompletionRegistry.RegisterBatchCompletion(ctx, (success, context) => callback(success));
-                var statusDetailBytes = EncodingUTF8.GetBytes(status.Detail);
+                var statusDetailBytes = MarshalUtils.GetBytesUTF8(status.Detail);
                 Native.grpcsharp_call_send_status_from_server(this, ctx, status.StatusCode, statusDetailBytes, new UIntPtr((ulong)statusDetailBytes.Length), metadataArray, sendEmptyInitialMetadata,
                     optionalPayload, optionalPayloadLength, writeFlags).CheckOk();
             }
@@ -204,6 +203,11 @@
             }
         }
 
+        public AuthContextSafeHandle GetAuthContext()
+        {
+            return Native.grpcsharp_call_auth_context(this);
+        }
+
         protected override bool ReleaseHandle()
         {
             Native.grpcsharp_call_destroy(handle);
diff --git a/src/csharp/Grpc.Core/Internal/MarshalUtils.cs b/src/csharp/Grpc.Core/Internal/MarshalUtils.cs
new file mode 100644
index 0000000..897e2f7
--- /dev/null
+++ b/src/csharp/Grpc.Core/Internal/MarshalUtils.cs
@@ -0,0 +1,90 @@
+#region Copyright notice and license
+
+// Copyright 2015, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#endregion
+
+using System;
+using System.Runtime.InteropServices;
+using System.Text;
+
+namespace Grpc.Core.Internal
+{
+    /// <summary>
+    /// Useful methods for native/managed marshalling.
+    /// </summary>
+    internal static class MarshalUtils
+    {
+        static readonly Encoding EncodingUTF8 = System.Text.Encoding.UTF8;
+        static readonly Encoding EncodingASCII = System.Text.Encoding.ASCII;
+
+        /// <summary>
+        /// Converts <c>IntPtr</c> pointing to a UTF-8 encoded byte array to <c>string</c>.
+        /// </summary>
+        public static string PtrToStringUTF8(IntPtr ptr, int len)
+        {
+            var bytes = new byte[len];
+            Marshal.Copy(ptr, bytes, 0, len);
+            return EncodingUTF8.GetString(bytes);
+        }
+
+        /// <summary>
+        /// Returns byte array containing UTF-8 encoding of given string.
+        /// </summary>
+        public static byte[] GetBytesUTF8(string str)
+        {
+            return EncodingUTF8.GetBytes(str);
+        }
+
+        /// <summary>
+        /// Get string from a UTF8 encoded byte array.
+        /// </summary>
+        public static string GetStringUTF8(byte[] bytes)
+        {
+            return EncodingUTF8.GetString(bytes);
+        }
+
+        /// <summary>
+        /// Returns byte array containing ASCII encoding of given string.
+        /// </summary>
+        public static byte[] GetBytesASCII(string str)
+        {
+            return EncodingASCII.GetBytes(str);
+        }
+
+        /// <summary>
+        /// Get string from an ASCII encoded byte array.
+        /// </summary>
+        public static string GetStringASCII(byte[] bytes)
+        {
+            return EncodingASCII.GetString(bytes);
+        }
+    }
+}
diff --git a/src/csharp/Grpc.Core/Internal/NativeMethods.cs b/src/csharp/Grpc.Core/Internal/NativeMethods.cs
index aff9550..dd65f05 100644
--- a/src/csharp/Grpc.Core/Internal/NativeMethods.cs
+++ b/src/csharp/Grpc.Core/Internal/NativeMethods.cs
@@ -148,6 +148,12 @@
         public readonly Delegates.grpcsharp_server_shutdown_and_notify_callback_delegate grpcsharp_server_shutdown_and_notify_callback;
         public readonly Delegates.grpcsharp_server_destroy_delegate grpcsharp_server_destroy;
 
+        public readonly Delegates.grpcsharp_call_auth_context_delegate grpcsharp_call_auth_context;
+        public readonly Delegates.grpcsharp_auth_context_peer_identity_property_name_delegate grpcsharp_auth_context_peer_identity_property_name;
+        public readonly Delegates.grpcsharp_auth_context_property_iterator_delegate grpcsharp_auth_context_property_iterator;
+        public readonly Delegates.grpcsharp_auth_property_iterator_next_delegate grpcsharp_auth_property_iterator_next;
+        public readonly Delegates.grpcsharp_auth_context_release_delegate grpcsharp_auth_context_release;
+
         public readonly Delegates.gprsharp_now_delegate gprsharp_now;
         public readonly Delegates.gprsharp_inf_future_delegate gprsharp_inf_future;
         public readonly Delegates.gprsharp_inf_past_delegate gprsharp_inf_past;
@@ -256,6 +262,12 @@
             this.grpcsharp_server_shutdown_and_notify_callback = GetMethodDelegate<Delegates.grpcsharp_server_shutdown_and_notify_callback_delegate>(library);
             this.grpcsharp_server_destroy = GetMethodDelegate<Delegates.grpcsharp_server_destroy_delegate>(library);
 
+            this.grpcsharp_call_auth_context = GetMethodDelegate<Delegates.grpcsharp_call_auth_context_delegate>(library);
+            this.grpcsharp_auth_context_peer_identity_property_name = GetMethodDelegate<Delegates.grpcsharp_auth_context_peer_identity_property_name_delegate>(library);
+            this.grpcsharp_auth_context_property_iterator = GetMethodDelegate<Delegates.grpcsharp_auth_context_property_iterator_delegate>(library);
+            this.grpcsharp_auth_property_iterator_next = GetMethodDelegate<Delegates.grpcsharp_auth_property_iterator_next_delegate>(library);
+            this.grpcsharp_auth_context_release = GetMethodDelegate<Delegates.grpcsharp_auth_context_release_delegate>(library);
+
             this.gprsharp_now = GetMethodDelegate<Delegates.gprsharp_now_delegate>(library);
             this.gprsharp_inf_future = GetMethodDelegate<Delegates.gprsharp_inf_future_delegate>(library);
             this.gprsharp_inf_past = GetMethodDelegate<Delegates.gprsharp_inf_past_delegate>(library);
@@ -404,6 +416,12 @@
             public delegate void grpcsharp_server_shutdown_and_notify_callback_delegate(ServerSafeHandle server, CompletionQueueSafeHandle cq, BatchContextSafeHandle ctx);
             public delegate void grpcsharp_server_destroy_delegate(IntPtr server);
 
+            public delegate AuthContextSafeHandle grpcsharp_call_auth_context_delegate(CallSafeHandle call);
+            public delegate IntPtr grpcsharp_auth_context_peer_identity_property_name_delegate(AuthContextSafeHandle authContext);  // returns const char*
+            public delegate AuthContextSafeHandle.NativeAuthPropertyIterator grpcsharp_auth_context_property_iterator_delegate(AuthContextSafeHandle authContext);
+            public delegate IntPtr grpcsharp_auth_property_iterator_next_delegate(ref AuthContextSafeHandle.NativeAuthPropertyIterator iterator);  // returns const auth_property*
+            public delegate void grpcsharp_auth_context_release_delegate(IntPtr authContext);
+
             public delegate Timespec gprsharp_now_delegate(ClockType clockType);
             public delegate Timespec gprsharp_inf_future_delegate(ClockType clockType);
             public delegate Timespec gprsharp_inf_past_delegate(ClockType clockType);