aboutsummaryrefslogtreecommitdiffhomepage
path: root/examples/objective-c/auth_sample
diff options
context:
space:
mode:
Diffstat (limited to 'examples/objective-c/auth_sample')
-rw-r--r--examples/objective-c/auth_sample/AuthSample.xcodeproj/project.pbxproj366
-rw-r--r--examples/objective-c/auth_sample/AuthSample.xcodeproj/project.xcworkspace/contents.xcworkspacedata7
-rw-r--r--examples/objective-c/auth_sample/AuthTestService.podspec35
-rw-r--r--examples/objective-c/auth_sample/MakeRPCViewController.h40
-rw-r--r--examples/objective-c/auth_sample/MakeRPCViewController.m100
-rw-r--r--examples/objective-c/auth_sample/Misc/AppDelegate.h38
-rw-r--r--examples/objective-c/auth_sample/Misc/AppDelegate.m61
-rw-r--r--examples/objective-c/auth_sample/Misc/Base.lproj/Main.storyboard154
-rw-r--r--examples/objective-c/auth_sample/Misc/GoogleService-Info.plist10
-rw-r--r--examples/objective-c/auth_sample/Misc/Images.xcassets/AppIcon.appiconset/Contents.json68
-rw-r--r--examples/objective-c/auth_sample/Misc/Images.xcassets/first.imageset/Contents.json12
-rw-r--r--examples/objective-c/auth_sample/Misc/Images.xcassets/first.imageset/first.pdfbin0 -> 2465 bytes
-rw-r--r--examples/objective-c/auth_sample/Misc/Images.xcassets/second.imageset/Contents.json12
-rw-r--r--examples/objective-c/auth_sample/Misc/Images.xcassets/second.imageset/second.pdfbin0 -> 2423 bytes
-rw-r--r--examples/objective-c/auth_sample/Misc/Info.plist80
-rw-r--r--examples/objective-c/auth_sample/Misc/main.m41
-rw-r--r--examples/objective-c/auth_sample/Podfile10
-rw-r--r--examples/objective-c/auth_sample/README.md189
-rw-r--r--examples/objective-c/auth_sample/SelectUserViewController.h42
-rw-r--r--examples/objective-c/auth_sample/SelectUserViewController.m86
20 files changed, 1351 insertions, 0 deletions
diff --git a/examples/objective-c/auth_sample/AuthSample.xcodeproj/project.pbxproj b/examples/objective-c/auth_sample/AuthSample.xcodeproj/project.pbxproj
new file mode 100644
index 0000000000..51a39c578c
--- /dev/null
+++ b/examples/objective-c/auth_sample/AuthSample.xcodeproj/project.pbxproj
@@ -0,0 +1,366 @@
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 46;
+ objects = {
+
+/* Begin PBXBuildFile section */
+ 63E1E9821B28CB2100EF0978 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 63E1E9811B28CB2100EF0978 /* main.m */; };
+ 63E1E9851B28CB2100EF0978 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 63E1E9841B28CB2100EF0978 /* AppDelegate.m */; };
+ 63E1E9881B28CB2100EF0978 /* SelectUserViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 63E1E9871B28CB2100EF0978 /* SelectUserViewController.m */; };
+ 63E1E98B1B28CB2100EF0978 /* MakeRPCViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 63E1E98A1B28CB2100EF0978 /* MakeRPCViewController.m */; };
+ 63E1E98E1B28CB2100EF0978 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 63E1E98C1B28CB2100EF0978 /* Main.storyboard */; };
+ 63E1E9901B28CB2100EF0978 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 63E1E98F1B28CB2100EF0978 /* Images.xcassets */; };
+ 63F5DE481B28F5C100CDD07E /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 63F5DE471B28F5C100CDD07E /* GoogleService-Info.plist */; };
+ 832213142AB24DB816D02635 /* libPods-AuthSample.a in Frameworks */ = {isa = PBXBuildFile; fileRef = F217A6ECA7F5BD1D5FB5071B /* libPods-AuthSample.a */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXFileReference section */
+ 63E1E97C1B28CB2100EF0978 /* AuthSample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = AuthSample.app; sourceTree = BUILT_PRODUCTS_DIR; };
+ 63E1E9801B28CB2100EF0978 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
+ 63E1E9811B28CB2100EF0978 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
+ 63E1E9831B28CB2100EF0978 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; };
+ 63E1E9841B28CB2100EF0978 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; };
+ 63E1E9861B28CB2100EF0978 /* SelectUserViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SelectUserViewController.h; sourceTree = "<group>"; };
+ 63E1E9871B28CB2100EF0978 /* SelectUserViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SelectUserViewController.m; sourceTree = "<group>"; };
+ 63E1E9891B28CB2100EF0978 /* MakeRPCViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MakeRPCViewController.h; sourceTree = "<group>"; };
+ 63E1E98A1B28CB2100EF0978 /* MakeRPCViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MakeRPCViewController.m; sourceTree = "<group>"; };
+ 63E1E98D1B28CB2100EF0978 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
+ 63E1E98F1B28CB2100EF0978 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = "<group>"; };
+ 63F5DE471B28F5C100CDD07E /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = "<group>"; };
+ A387D6CECBCF2EAF2983033A /* Pods-AuthSample.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AuthSample.debug.xcconfig"; path = "Pods/Target Support Files/Pods-AuthSample/Pods-AuthSample.debug.xcconfig"; sourceTree = "<group>"; };
+ B444176735DA81FBE4B8B80C /* Pods-AuthSample.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AuthSample.release.xcconfig"; path = "Pods/Target Support Files/Pods-AuthSample/Pods-AuthSample.release.xcconfig"; sourceTree = "<group>"; };
+ F217A6ECA7F5BD1D5FB5071B /* libPods-AuthSample.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-AuthSample.a"; sourceTree = BUILT_PRODUCTS_DIR; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+ 63E1E9791B28CB2000EF0978 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 832213142AB24DB816D02635 /* libPods-AuthSample.a in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+ 021FA0E0B3F5D3D477DDAC10 /* Pods */ = {
+ isa = PBXGroup;
+ children = (
+ A387D6CECBCF2EAF2983033A /* Pods-AuthSample.debug.xcconfig */,
+ B444176735DA81FBE4B8B80C /* Pods-AuthSample.release.xcconfig */,
+ );
+ name = Pods;
+ sourceTree = "<group>";
+ };
+ 4F443572636F3D60F26E870D /* Frameworks */ = {
+ isa = PBXGroup;
+ children = (
+ F217A6ECA7F5BD1D5FB5071B /* libPods-AuthSample.a */,
+ );
+ name = Frameworks;
+ sourceTree = "<group>";
+ };
+ 63E1E9731B28CB2000EF0978 = {
+ isa = PBXGroup;
+ children = (
+ 63E1E97E1B28CB2100EF0978 /* AuthSample */,
+ 63E1E97D1B28CB2100EF0978 /* Products */,
+ 021FA0E0B3F5D3D477DDAC10 /* Pods */,
+ 4F443572636F3D60F26E870D /* Frameworks */,
+ );
+ sourceTree = "<group>";
+ };
+ 63E1E97D1B28CB2100EF0978 /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ 63E1E97C1B28CB2100EF0978 /* AuthSample.app */,
+ );
+ name = Products;
+ sourceTree = "<group>";
+ };
+ 63E1E97E1B28CB2100EF0978 /* AuthSample */ = {
+ isa = PBXGroup;
+ children = (
+ 63E1E9861B28CB2100EF0978 /* SelectUserViewController.h */,
+ 63E1E9871B28CB2100EF0978 /* SelectUserViewController.m */,
+ 63E1E9891B28CB2100EF0978 /* MakeRPCViewController.h */,
+ 63E1E98A1B28CB2100EF0978 /* MakeRPCViewController.m */,
+ 63E1E97F1B28CB2100EF0978 /* Supporting Files */,
+ );
+ name = AuthSample;
+ sourceTree = SOURCE_ROOT;
+ };
+ 63E1E97F1B28CB2100EF0978 /* Supporting Files */ = {
+ isa = PBXGroup;
+ children = (
+ 63E1E98C1B28CB2100EF0978 /* Main.storyboard */,
+ 63F5DE471B28F5C100CDD07E /* GoogleService-Info.plist */,
+ 63E1E98F1B28CB2100EF0978 /* Images.xcassets */,
+ 63E1E9801B28CB2100EF0978 /* Info.plist */,
+ 63E1E9831B28CB2100EF0978 /* AppDelegate.h */,
+ 63E1E9841B28CB2100EF0978 /* AppDelegate.m */,
+ 63E1E9811B28CB2100EF0978 /* main.m */,
+ );
+ name = "Supporting Files";
+ path = Misc;
+ sourceTree = "<group>";
+ };
+/* End PBXGroup section */
+
+/* Begin PBXNativeTarget section */
+ 63E1E97B1B28CB2000EF0978 /* AuthSample */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 63E1E9A21B28CB2100EF0978 /* Build configuration list for PBXNativeTarget "AuthSample" */;
+ buildPhases = (
+ DAABBA7B5788A39108D7CA83 /* Check Pods Manifest.lock */,
+ 63E1E9781B28CB2000EF0978 /* Sources */,
+ 63E1E9791B28CB2000EF0978 /* Frameworks */,
+ 63E1E97A1B28CB2000EF0978 /* Resources */,
+ AEFCCC69DD59CE8F6EB769D7 /* Copy Pods Resources */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = AuthSample;
+ productName = AuthSample;
+ productReference = 63E1E97C1B28CB2100EF0978 /* AuthSample.app */;
+ productType = "com.apple.product-type.application";
+ };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+ 63E1E9741B28CB2000EF0978 /* Project object */ = {
+ isa = PBXProject;
+ attributes = {
+ LastUpgradeCheck = 0630;
+ ORGANIZATIONNAME = gRPC;
+ TargetAttributes = {
+ 63E1E97B1B28CB2000EF0978 = {
+ CreatedOnToolsVersion = 6.3.1;
+ };
+ };
+ };
+ buildConfigurationList = 63E1E9771B28CB2000EF0978 /* Build configuration list for PBXProject "AuthSample" */;
+ compatibilityVersion = "Xcode 3.2";
+ developmentRegion = English;
+ hasScannedForEncodings = 0;
+ knownRegions = (
+ en,
+ Base,
+ );
+ mainGroup = 63E1E9731B28CB2000EF0978;
+ productRefGroup = 63E1E97D1B28CB2100EF0978 /* Products */;
+ projectDirPath = "";
+ projectRoot = "";
+ targets = (
+ 63E1E97B1B28CB2000EF0978 /* AuthSample */,
+ );
+ };
+/* End PBXProject section */
+
+/* Begin PBXResourcesBuildPhase section */
+ 63E1E97A1B28CB2000EF0978 /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 63E1E98E1B28CB2100EF0978 /* Main.storyboard in Resources */,
+ 63E1E9901B28CB2100EF0978 /* Images.xcassets in Resources */,
+ 63F5DE481B28F5C100CDD07E /* GoogleService-Info.plist in Resources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXResourcesBuildPhase section */
+
+/* Begin PBXShellScriptBuildPhase section */
+ AEFCCC69DD59CE8F6EB769D7 /* Copy Pods Resources */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ );
+ name = "Copy Pods Resources";
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-AuthSample/Pods-AuthSample-resources.sh\"\n";
+ showEnvVarsInLog = 0;
+ };
+ DAABBA7B5788A39108D7CA83 /* Check Pods Manifest.lock */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ );
+ name = "Check Pods Manifest.lock";
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n";
+ showEnvVarsInLog = 0;
+ };
+/* End PBXShellScriptBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+ 63E1E9781B28CB2000EF0978 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 63E1E98B1B28CB2100EF0978 /* MakeRPCViewController.m in Sources */,
+ 63E1E9851B28CB2100EF0978 /* AppDelegate.m in Sources */,
+ 63E1E9881B28CB2100EF0978 /* SelectUserViewController.m in Sources */,
+ 63E1E9821B28CB2100EF0978 /* main.m in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin PBXVariantGroup section */
+ 63E1E98C1B28CB2100EF0978 /* Main.storyboard */ = {
+ isa = PBXVariantGroup;
+ children = (
+ 63E1E98D1B28CB2100EF0978 /* Base */,
+ );
+ name = Main.storyboard;
+ sourceTree = "<group>";
+ };
+/* End PBXVariantGroup section */
+
+/* Begin XCBuildConfiguration section */
+ 63E1E9A01B28CB2100EF0978 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+ COPY_PHASE_STRIP = NO;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_NO_COMMON_BLOCKS = YES;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "DEBUG=1",
+ "$(inherited)",
+ );
+ GCC_SYMBOLS_PRIVATE_EXTERN = NO;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ IPHONEOS_DEPLOYMENT_TARGET = 8.3;
+ MTL_ENABLE_DEBUG_INFO = YES;
+ ONLY_ACTIVE_ARCH = YES;
+ SDKROOT = iphoneos;
+ TARGETED_DEVICE_FAMILY = "1,2";
+ };
+ name = Debug;
+ };
+ 63E1E9A11B28CB2100EF0978 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+ COPY_PHASE_STRIP = NO;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ ENABLE_NS_ASSERTIONS = NO;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_NO_COMMON_BLOCKS = YES;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ IPHONEOS_DEPLOYMENT_TARGET = 8.3;
+ MTL_ENABLE_DEBUG_INFO = NO;
+ SDKROOT = iphoneos;
+ TARGETED_DEVICE_FAMILY = "1,2";
+ VALIDATE_PRODUCT = YES;
+ };
+ name = Release;
+ };
+ 63E1E9A31B28CB2100EF0978 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = A387D6CECBCF2EAF2983033A /* Pods-AuthSample.debug.xcconfig */;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ INFOPLIST_FILE = Misc/Info.plist;
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Debug;
+ };
+ 63E1E9A41B28CB2100EF0978 /* Release */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = B444176735DA81FBE4B8B80C /* Pods-AuthSample.release.xcconfig */;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ INFOPLIST_FILE = Misc/Info.plist;
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+ 63E1E9771B28CB2000EF0978 /* Build configuration list for PBXProject "AuthSample" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 63E1E9A01B28CB2100EF0978 /* Debug */,
+ 63E1E9A11B28CB2100EF0978 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 63E1E9A21B28CB2100EF0978 /* Build configuration list for PBXNativeTarget "AuthSample" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 63E1E9A31B28CB2100EF0978 /* Debug */,
+ 63E1E9A41B28CB2100EF0978 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+/* End XCConfigurationList section */
+ };
+ rootObject = 63E1E9741B28CB2000EF0978 /* Project object */;
+}
diff --git a/examples/objective-c/auth_sample/AuthSample.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/examples/objective-c/auth_sample/AuthSample.xcodeproj/project.xcworkspace/contents.xcworkspacedata
new file mode 100644
index 0000000000..39b57a4b33
--- /dev/null
+++ b/examples/objective-c/auth_sample/AuthSample.xcodeproj/project.xcworkspace/contents.xcworkspacedata
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Workspace
+ version = "1.0">
+ <FileRef
+ location = "self:AuthSample.xcodeproj">
+ </FileRef>
+</Workspace>
diff --git a/examples/objective-c/auth_sample/AuthTestService.podspec b/examples/objective-c/auth_sample/AuthTestService.podspec
new file mode 100644
index 0000000000..9f2a2cc361
--- /dev/null
+++ b/examples/objective-c/auth_sample/AuthTestService.podspec
@@ -0,0 +1,35 @@
+Pod::Spec.new do |s|
+ s.name = "AuthTestService"
+ s.version = "0.0.1"
+ s.license = "New BSD"
+
+ s.ios.deployment_target = "6.0"
+ s.osx.deployment_target = "10.8"
+
+ # Base directory where the .proto files are.
+ src = "../../protos"
+
+ # Directory where the generated files will be place.
+ dir = "Pods/" + s.name
+
+ # Run protoc with the Objective-C and gRPC plugins to generate protocol messages and gRPC clients.
+ s.prepare_command = <<-CMD
+ mkdir -p #{dir}
+ protoc -I #{src} --objc_out=#{dir} --objcgrpc_out=#{dir} #{src}/auth_sample.proto
+ CMD
+
+ s.subspec "Messages" do |ms|
+ ms.source_files = "#{dir}/*.pbobjc.{h,m}", "#{dir}/**/*.pbobjc.{h,m}"
+ ms.header_mappings_dir = dir
+ ms.requires_arc = false
+ ms.dependency "Protobuf", "~> 3.0.0-alpha-3"
+ end
+
+ s.subspec "Services" do |ss|
+ ss.source_files = "#{dir}/*.pbrpc.{h,m}", "#{dir}/**/*.pbrpc.{h,m}"
+ ss.header_mappings_dir = dir
+ ss.requires_arc = true
+ ss.dependency "gRPC", "~> 0.6"
+ ss.dependency "#{s.name}/Messages"
+ end
+end
diff --git a/examples/objective-c/auth_sample/MakeRPCViewController.h b/examples/objective-c/auth_sample/MakeRPCViewController.h
new file mode 100644
index 0000000000..c75a8b3180
--- /dev/null
+++ b/examples/objective-c/auth_sample/MakeRPCViewController.h
@@ -0,0 +1,40 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+#import <UIKit/UIKit.h>
+
+extern NSString * const kTestScope;
+
+@interface MakeRPCViewController : UIViewController
+@property(weak, nonatomic) IBOutlet UILabel *mainLabel;
+@end
diff --git a/examples/objective-c/auth_sample/MakeRPCViewController.m b/examples/objective-c/auth_sample/MakeRPCViewController.m
new file mode 100644
index 0000000000..366bc9deea
--- /dev/null
+++ b/examples/objective-c/auth_sample/MakeRPCViewController.m
@@ -0,0 +1,100 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+#import "MakeRPCViewController.h"
+
+#import <AuthTestService/AuthSample.pbrpc.h>
+#import <Google/SignIn.h>
+#include <grpc/status.h>
+#import <ProtoRPC/ProtoRPC.h>
+
+NSString * const kTestScope = @"https://www.googleapis.com/auth/xapi.zoo";
+
+static NSString * const kTestHostAddress = @"grpc-test.sandbox.google.com";
+
+// Category for RPC errors to create the descriptions as we want them to appear on our view.
+@interface NSError (AuthSample)
+- (NSString *)UIDescription;
+@end
+
+@implementation NSError (AuthSample)
+- (NSString *)UIDescription {
+ if (self.code == GRPC_STATUS_UNAUTHENTICATED) {
+ // Authentication error. OAuth2 specifies we'll receive a challenge header.
+ // |userInfo[kGRPCStatusMetadataKey]| is the dictionary of response metadata.
+ NSString *challengeHeader = self.userInfo[kGRPCStatusMetadataKey][@"www-authenticate"] ?: @"";
+ return [@"Invalid credentials. Server challenge:\n" stringByAppendingString:challengeHeader];
+ } else {
+ // Any other error.
+ return [NSString stringWithFormat:@"Unexpected RPC error %li: %@",
+ (long)self.code, self.localizedDescription];
+ }
+}
+@end
+
+@implementation MakeRPCViewController
+
+- (void)viewWillAppear:(BOOL)animated {
+
+ // Create a service client and a proto request as usual.
+ AUTHTestService *client = [[AUTHTestService alloc] initWithHost:kTestHostAddress];
+
+ AUTHRequest *request = [AUTHRequest message];
+ request.fillUsername = YES;
+ request.fillOauthScope = YES;
+
+ // Create a not-yet-started RPC. We want to set the request headers on this object before starting
+ // it.
+ ProtoRPC *call =
+ [client RPCToUnaryCallWithRequest:request handler:^(AUTHResponse *response, NSError *error) {
+ if (response) {
+ // This test server responds with the email and scope of the access token it receives.
+ self.mainLabel.text = [NSString stringWithFormat:@"Used scope: %@ on behalf of user %@",
+ response.oauthScope, response.username];
+
+ } else {
+ self.mainLabel.text = error.UIDescription;
+ }
+ }];
+
+ // Set the access token to be used.
+ NSString *accessToken = GIDSignIn.sharedInstance.currentUser.authentication.accessToken;
+ call.requestMetadata[@"Authorization"] = [@"Bearer " stringByAppendingString:accessToken];
+
+ // Start the RPC.
+ [call start];
+
+ self.mainLabel.text = @"Waiting for RPC to complete...";
+}
+
+@end
diff --git a/examples/objective-c/auth_sample/Misc/AppDelegate.h b/examples/objective-c/auth_sample/Misc/AppDelegate.h
new file mode 100644
index 0000000000..102e7f3ade
--- /dev/null
+++ b/examples/objective-c/auth_sample/Misc/AppDelegate.h
@@ -0,0 +1,38 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+#import <UIKit/UIKit.h>
+
+@interface AppDelegate : UIResponder <UIApplicationDelegate>
+@property (strong, nonatomic) UIWindow *window;
+@end
diff --git a/examples/objective-c/auth_sample/Misc/AppDelegate.m b/examples/objective-c/auth_sample/Misc/AppDelegate.m
new file mode 100644
index 0000000000..798d342938
--- /dev/null
+++ b/examples/objective-c/auth_sample/Misc/AppDelegate.m
@@ -0,0 +1,61 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+#import "AppDelegate.h"
+
+#import <Google/SignIn.h>
+
+@implementation AppDelegate
+
+// As instructed in https://developers.google.com/identity/sign-in/ios/sign-in
+- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
+ NSError* configureError;
+ [GGLContext.sharedInstance configureWithError: &configureError];
+ NSAssert(!configureError, @"Error configuring Google services: %@", configureError);
+
+ return YES;
+}
+
+// As instructed in https://developers.google.com/identity/sign-in/ios/sign-in
+- (BOOL)application:(UIApplication *)application
+ openURL:(NSURL *)url
+ sourceApplication:(NSString *)sourceApplication
+ annotation:(id)annotation {
+ // This will properly handle the URL that the application receives at the end of the
+ // authentication process.
+ return [GIDSignIn.sharedInstance handleURL:url
+ sourceApplication:sourceApplication
+ annotation:annotation];
+}
+
+@end
diff --git a/examples/objective-c/auth_sample/Misc/Base.lproj/Main.storyboard b/examples/objective-c/auth_sample/Misc/Base.lproj/Main.storyboard
new file mode 100644
index 0000000000..fb29c124e2
--- /dev/null
+++ b/examples/objective-c/auth_sample/Misc/Base.lproj/Main.storyboard
@@ -0,0 +1,154 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="7702" systemVersion="14D131" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="49e-Tb-3d3">
+ <dependencies>
+ <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="7701"/>
+ <capability name="Constraints to layout margins" minToolsVersion="6.0"/>
+ </dependencies>
+ <scenes>
+ <!--Select User-->
+ <scene sceneID="hNz-n2-bh7">
+ <objects>
+ <viewController id="9pv-A4-QxB" userLabel="Select User" customClass="SelectUserViewController" sceneMemberID="viewController">
+ <layoutGuides>
+ <viewControllerLayoutGuide type="top" id="Ia1-K6-d13"/>
+ <viewControllerLayoutGuide type="bottom" id="4ug-Mw-9AY"/>
+ </layoutGuides>
+ <view key="view" contentMode="scaleToFill" id="tsR-hK-woN">
+ <rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
+ <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+ <subviews>
+ <label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleToFill" text="Please sign in." textAlignment="center" lineBreakMode="tailTruncation" minimumFontSize="10" translatesAutoresizingMaskIntoConstraints="NO" id="KQZ-1w-vlD" userLabel="Main Label">
+ <rect key="frame" x="222" y="190" width="157" height="28"/>
+ <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
+ <fontDescription key="fontDescription" name="Helvetica" family="Helvetica" pointSize="24"/>
+ <color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
+ <nil key="highlightedColor"/>
+ </label>
+ <label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="A5M-7J-77L" userLabel="Sub Label">
+ <rect key="frame" x="301" y="226" width="0.0" height="0.0"/>
+ <fontDescription key="fontDescription" type="system" pointSize="14"/>
+ <color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
+ <nil key="highlightedColor"/>
+ </label>
+ <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="W20-aa-6Xr">
+ <rect key="frame" x="150" y="370" width="300" height="50"/>
+ <subviews>
+ <view contentMode="center" translatesAutoresizingMaskIntoConstraints="NO" id="25e-pE-eb8" customClass="GIDSignInButton">
+ <rect key="frame" x="42" y="0.0" width="216" height="77"/>
+ <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
+ <constraints>
+ <constraint firstAttribute="width" constant="216" placeholder="YES" id="Gfn-Hn-HXd"/>
+ <constraint firstAttribute="height" constant="77" placeholder="YES" id="cy1-xY-er0"/>
+ </constraints>
+ </view>
+ <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="RKb-EE-mCZ">
+ <rect key="frame" x="0.0" y="0.0" width="300" height="42"/>
+ <color key="backgroundColor" red="0.0" green="0.50196081399917603" blue="1" alpha="1" colorSpace="calibratedRGB"/>
+ <constraints>
+ <constraint firstAttribute="width" constant="300" id="ILy-QC-YPq"/>
+ <constraint firstAttribute="height" constant="42" id="MFs-aL-fQF"/>
+ </constraints>
+ <fontDescription key="fontDescription" type="boldSystem" pointSize="14"/>
+ <color key="tintColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
+ <state key="normal" title="Sign out">
+ <color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
+ </state>
+ <connections>
+ <action selector="didTapSignOut" destination="9pv-A4-QxB" eventType="touchUpInside" id="lcC-7k-Rki"/>
+ </connections>
+ </button>
+ </subviews>
+ <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
+ <constraints>
+ <constraint firstAttribute="centerX" secondItem="25e-pE-eb8" secondAttribute="centerX" id="47f-A8-C2R"/>
+ <constraint firstAttribute="height" constant="50" id="EDJ-oo-Ix4"/>
+ <constraint firstItem="25e-pE-eb8" firstAttribute="top" secondItem="W20-aa-6Xr" secondAttribute="top" id="KSP-qb-mCJ"/>
+ <constraint firstItem="RKb-EE-mCZ" firstAttribute="top" secondItem="W20-aa-6Xr" secondAttribute="top" id="QDr-HV-DXb"/>
+ <constraint firstAttribute="width" constant="300" id="zWU-pZ-oQ7"/>
+ <constraint firstAttribute="centerX" secondItem="RKb-EE-mCZ" secondAttribute="centerX" id="zwy-cD-xao"/>
+ </constraints>
+ </view>
+ </subviews>
+ <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
+ <constraints>
+ <constraint firstAttribute="centerX" secondItem="KQZ-1w-vlD" secondAttribute="centerX" id="6BV-lF-sBN"/>
+ <constraint firstItem="KQZ-1w-vlD" firstAttribute="top" secondItem="Ia1-K6-d13" secondAttribute="bottom" constant="170" id="82x-jY-eWa"/>
+ <constraint firstAttribute="centerX" secondItem="W20-aa-6Xr" secondAttribute="centerX" id="aHL-Ts-LoW"/>
+ <constraint firstItem="A5M-7J-77L" firstAttribute="top" secondItem="KQZ-1w-vlD" secondAttribute="bottom" constant="8" symbolic="YES" id="cfb-er-3JN"/>
+ <constraint firstItem="A5M-7J-77L" firstAttribute="centerX" secondItem="KQZ-1w-vlD" secondAttribute="centerX" id="e1l-AV-tCB"/>
+ <constraint firstItem="W20-aa-6Xr" firstAttribute="top" secondItem="Ia1-K6-d13" secondAttribute="bottom" constant="350" id="pab-Li-xZ5"/>
+ </constraints>
+ </view>
+ <tabBarItem key="tabBarItem" title="Select User" image="first" id="acW-dT-cKf"/>
+ <connections>
+ <outlet property="mainLabel" destination="KQZ-1w-vlD" id="fWK-H9-WXN"/>
+ <outlet property="signInButton" destination="25e-pE-eb8" id="ovt-t5-7BV"/>
+ <outlet property="signOutButton" destination="RKb-EE-mCZ" id="afy-Q6-rK8"/>
+ <outlet property="subLabel" destination="A5M-7J-77L" id="DIj-ZX-1NK"/>
+ </connections>
+ </viewController>
+ <placeholder placeholderIdentifier="IBFirstResponder" id="W5J-7L-Pyd" sceneMemberID="firstResponder"/>
+ </objects>
+ <point key="canvasLocation" x="750" y="-320"/>
+ </scene>
+ <!--Make RPC-->
+ <scene sceneID="wg7-f3-ORb">
+ <objects>
+ <viewController id="8rJ-Kc-sve" userLabel="Make RPC" customClass="MakeRPCViewController" sceneMemberID="viewController">
+ <layoutGuides>
+ <viewControllerLayoutGuide type="top" id="L7p-HK-0SC"/>
+ <viewControllerLayoutGuide type="bottom" id="Djb-ko-YwX"/>
+ </layoutGuides>
+ <view key="view" contentMode="scaleToFill" id="QS5-Rx-YEW">
+ <rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
+ <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+ <subviews>
+ <label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleToFill" misplaced="YES" text="Waiting for RPC to complete..." lineBreakMode="wordWrap" numberOfLines="0" minimumFontSize="10" translatesAutoresizingMaskIntoConstraints="NO" id="zEq-FU-wV5">
+ <rect key="frame" x="16" y="286" width="568" height="28"/>
+ <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
+ <fontDescription key="fontDescription" name="Helvetica" family="Helvetica" pointSize="18"/>
+ <color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
+ <nil key="highlightedColor"/>
+ </label>
+ </subviews>
+ <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
+ <constraints>
+ <constraint firstItem="zEq-FU-wV5" firstAttribute="leading" secondItem="QS5-Rx-YEW" secondAttribute="leadingMargin" id="173-PJ-A9Y"/>
+ <constraint firstAttribute="trailingMargin" secondItem="zEq-FU-wV5" secondAttribute="trailing" id="Tct-jU-lL7"/>
+ <constraint firstAttribute="centerY" secondItem="zEq-FU-wV5" secondAttribute="centerY" id="qzY-Ky-pLD"/>
+ </constraints>
+ </view>
+ <tabBarItem key="tabBarItem" title="Make RPC" image="second" id="cPa-gy-q4n" userLabel="Make RPC"/>
+ <connections>
+ <outlet property="mainLabel" destination="zEq-FU-wV5" id="l1H-U6-oAa"/>
+ </connections>
+ </viewController>
+ <placeholder placeholderIdentifier="IBFirstResponder" id="4Nw-L8-lE0" sceneMemberID="firstResponder"/>
+ </objects>
+ <point key="canvasLocation" x="750" y="360"/>
+ </scene>
+ <!--Tab Bar Controller-->
+ <scene sceneID="yl2-sM-qoP">
+ <objects>
+ <tabBarController id="49e-Tb-3d3" sceneMemberID="viewController">
+ <nil key="simulatedBottomBarMetrics"/>
+ <tabBar key="tabBar" contentMode="scaleToFill" id="W28-zg-YXA">
+ <rect key="frame" x="0.0" y="975" width="768" height="49"/>
+ <autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
+ <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
+ </tabBar>
+ <connections>
+ <segue destination="9pv-A4-QxB" kind="relationship" relationship="viewControllers" id="u7Y-xg-7CH"/>
+ <segue destination="8rJ-Kc-sve" kind="relationship" relationship="viewControllers" id="lzU-1b-eKA"/>
+ </connections>
+ </tabBarController>
+ <placeholder placeholderIdentifier="IBFirstResponder" id="HuB-VB-40B" sceneMemberID="firstResponder"/>
+ </objects>
+ <point key="canvasLocation" x="0.0" y="0.0"/>
+ </scene>
+ </scenes>
+ <resources>
+ <image name="first" width="30" height="30"/>
+ <image name="second" width="30" height="30"/>
+ </resources>
+</document>
diff --git a/examples/objective-c/auth_sample/Misc/GoogleService-Info.plist b/examples/objective-c/auth_sample/Misc/GoogleService-Info.plist
new file mode 100644
index 0000000000..86909d84a3
--- /dev/null
+++ b/examples/objective-c/auth_sample/Misc/GoogleService-Info.plist
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CLIENT_ID</key>
+ <string>15087385131-lh9bpkiai9nls53uadju0if6k7un3uih.apps.googleusercontent.com</string>
+ <key>REVERSED_CLIENT_ID</key>
+ <string>com.googleusercontent.apps.15087385131-lh9bpkiai9nls53uadju0if6k7un3uih</string>
+</dict>
+</plist> \ No newline at end of file
diff --git a/examples/objective-c/auth_sample/Misc/Images.xcassets/AppIcon.appiconset/Contents.json b/examples/objective-c/auth_sample/Misc/Images.xcassets/AppIcon.appiconset/Contents.json
new file mode 100644
index 0000000000..36d2c80d88
--- /dev/null
+++ b/examples/objective-c/auth_sample/Misc/Images.xcassets/AppIcon.appiconset/Contents.json
@@ -0,0 +1,68 @@
+{
+ "images" : [
+ {
+ "idiom" : "iphone",
+ "size" : "29x29",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "iphone",
+ "size" : "29x29",
+ "scale" : "3x"
+ },
+ {
+ "idiom" : "iphone",
+ "size" : "40x40",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "iphone",
+ "size" : "40x40",
+ "scale" : "3x"
+ },
+ {
+ "idiom" : "iphone",
+ "size" : "60x60",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "iphone",
+ "size" : "60x60",
+ "scale" : "3x"
+ },
+ {
+ "idiom" : "ipad",
+ "size" : "29x29",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "ipad",
+ "size" : "29x29",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "ipad",
+ "size" : "40x40",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "ipad",
+ "size" : "40x40",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "ipad",
+ "size" : "76x76",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "ipad",
+ "size" : "76x76",
+ "scale" : "2x"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+} \ No newline at end of file
diff --git a/examples/objective-c/auth_sample/Misc/Images.xcassets/first.imageset/Contents.json b/examples/objective-c/auth_sample/Misc/Images.xcassets/first.imageset/Contents.json
new file mode 100644
index 0000000000..33a745102c
--- /dev/null
+++ b/examples/objective-c/auth_sample/Misc/Images.xcassets/first.imageset/Contents.json
@@ -0,0 +1,12 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "filename" : "first.pdf"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+} \ No newline at end of file
diff --git a/examples/objective-c/auth_sample/Misc/Images.xcassets/first.imageset/first.pdf b/examples/objective-c/auth_sample/Misc/Images.xcassets/first.imageset/first.pdf
new file mode 100644
index 0000000000..47d911dea6
--- /dev/null
+++ b/examples/objective-c/auth_sample/Misc/Images.xcassets/first.imageset/first.pdf
Binary files differ
diff --git a/examples/objective-c/auth_sample/Misc/Images.xcassets/second.imageset/Contents.json b/examples/objective-c/auth_sample/Misc/Images.xcassets/second.imageset/Contents.json
new file mode 100644
index 0000000000..03bd9c927f
--- /dev/null
+++ b/examples/objective-c/auth_sample/Misc/Images.xcassets/second.imageset/Contents.json
@@ -0,0 +1,12 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "filename" : "second.pdf"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+} \ No newline at end of file
diff --git a/examples/objective-c/auth_sample/Misc/Images.xcassets/second.imageset/second.pdf b/examples/objective-c/auth_sample/Misc/Images.xcassets/second.imageset/second.pdf
new file mode 100644
index 0000000000..401614e288
--- /dev/null
+++ b/examples/objective-c/auth_sample/Misc/Images.xcassets/second.imageset/second.pdf
Binary files differ
diff --git a/examples/objective-c/auth_sample/Misc/Info.plist b/examples/objective-c/auth_sample/Misc/Info.plist
new file mode 100644
index 0000000000..fc292507c7
--- /dev/null
+++ b/examples/objective-c/auth_sample/Misc/Info.plist
@@ -0,0 +1,80 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>en</string>
+ <key>CFBundleExecutable</key>
+ <string>$(EXECUTABLE_NAME)</string>
+ <key>CFBundleIdentifier</key>
+ <string>io.grpc.$(PRODUCT_NAME:rfc1034identifier)</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundleName</key>
+ <string>$(PRODUCT_NAME)</string>
+ <key>CFBundlePackageType</key>
+ <string>APPL</string>
+ <key>CFBundleShortVersionString</key>
+ <string>1.0</string>
+ <key>CFBundleSignature</key>
+ <string>????</string>
+ <key>CFBundleURLTypes</key>
+ <array>
+ <dict>
+ <key>CFBundleTypeRole</key>
+ <string>Editor</string>
+ <key>CFBundleURLName</key>
+ <string>REVERSED_CLIENT_ID</string>
+ <key>CFBundleURLSchemes</key>
+ <array>
+ <string>com.googleusercontent.apps.15087385131-lh9bpkiai9nls53uadju0if6k7un3uih</string>
+ </array>
+ </dict>
+ <dict>
+ <key>CFBundleTypeRole</key>
+ <string>Editor</string>
+ <key>CFBundleURLName</key>
+ <string>BUNDLE_ID</string>
+ <key>CFBundleURLSchemes</key>
+ <array>
+ <string>io.grpc.AuthSample</string>
+ </array>
+ </dict>
+ </array>
+ <key>CFBundleVersion</key>
+ <string>1</string>
+ <key>LSRequiresIPhoneOS</key>
+ <true/>
+ <key>UILaunchStoryboardName</key>
+ <string>Main</string>
+ <key>UIMainStoryboardFile</key>
+ <string>Main</string>
+ <key>UIRequiredDeviceCapabilities</key>
+ <array>
+ <string>armv7</string>
+ </array>
+ <key>UIStatusBarTintParameters</key>
+ <dict>
+ <key>UINavigationBar</key>
+ <dict>
+ <key>Style</key>
+ <string>UIBarStyleDefault</string>
+ <key>Translucent</key>
+ <false/>
+ </dict>
+ </dict>
+ <key>UISupportedInterfaceOrientations</key>
+ <array>
+ <string>UIInterfaceOrientationPortrait</string>
+ <string>UIInterfaceOrientationLandscapeLeft</string>
+ <string>UIInterfaceOrientationLandscapeRight</string>
+ </array>
+ <key>UISupportedInterfaceOrientations~ipad</key>
+ <array>
+ <string>UIInterfaceOrientationPortrait</string>
+ <string>UIInterfaceOrientationPortraitUpsideDown</string>
+ <string>UIInterfaceOrientationLandscapeLeft</string>
+ <string>UIInterfaceOrientationLandscapeRight</string>
+ </array>
+</dict>
+</plist>
diff --git a/examples/objective-c/auth_sample/Misc/main.m b/examples/objective-c/auth_sample/Misc/main.m
new file mode 100644
index 0000000000..81e9d44e54
--- /dev/null
+++ b/examples/objective-c/auth_sample/Misc/main.m
@@ -0,0 +1,41 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+#import <UIKit/UIKit.h>
+#import "AppDelegate.h"
+
+int main(int argc, char * argv[]) {
+ @autoreleasepool {
+ return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
+ }
+}
diff --git a/examples/objective-c/auth_sample/Podfile b/examples/objective-c/auth_sample/Podfile
new file mode 100644
index 0000000000..dd4fd558c0
--- /dev/null
+++ b/examples/objective-c/auth_sample/Podfile
@@ -0,0 +1,10 @@
+source 'https://github.com/CocoaPods/Specs.git'
+platform :ios, '8.0'
+
+target 'AuthSample' do
+ # Depend on the generated AuthTestService library.
+ pod 'AuthTestService', :path => '.'
+
+ # Depend on Google's OAuth2 library
+ pod 'Google/SignIn'
+end
diff --git a/examples/objective-c/auth_sample/README.md b/examples/objective-c/auth_sample/README.md
new file mode 100644
index 0000000000..3dbe7e334c
--- /dev/null
+++ b/examples/objective-c/auth_sample/README.md
@@ -0,0 +1,189 @@
+#OAuth2 on gRPC: Objective-C
+
+This example application demostrates how to use OAuth2 on gRPC to make authenticated API calls on
+behalf of a user. By walking through it you'll learn how to use the Objective-C gRPC API to:
+
+- Initialize and configure a remote call object before the RPC is started.
+- Set request metadata elements on a call, which are semantically equivalent to HTTP request
+headers.
+- Read response metadata from a call, which is equivalent to HTTP response headers and trailers.
+
+It assumes you know the basics on how to make gRPC API calls using the Objective-C client library,
+as shown in the [Hello World](examples/objective-c/helloworld)
+or [Route Guide](examples/objective-c/route_guide) tutorials,
+and are familiar with OAuth2 concepts like _access token_.
+
+- [Example code and setup](#setup)
+- [Try it out!](#try)
+- [Create an RPC object and start it later](#rpc-object)
+- [Set request metadata of a call: Authorization header with an access token](#request-metadata)
+- [Get response metadata of a call: Auth challenge header](#response-metadata)
+
+<a name="setup"></a>
+## Example code and setup
+
+The example code for our tutorial is in [examples/objective-c/auth_sample](examples/objective-c/auth_sample).
+To download the example, clone this repository by running the following command:
+```shell
+$ git clone https://github.com/grpc/grpc.git
+```
+
+Then change your current directory to `examples/objective-c/auth_sample`:
+```shell
+$ cd examples/objective-c/auth_sample
+```
+
+Our example is a simple application with two views. The first one lets a user sign in and out using
+the OAuth2 flow of Google's [iOS SignIn library](https://developers.google.com/identity/sign-in/ios/).
+(Google's library is used in this example because the test gRPC service we are going to call expects
+Google account credentials, but neither gRPC nor the Objective-C client library is tied to any
+specific OAuth2 provider). The second view makes a gRPC request to the test server, using the
+access token obtained by the first view.
+
+Note: OAuth2 libraries need the application to register and obtain an ID from the identity provider
+(in the case of this example app, Google). The app's XCode project is configured using that ID, so
+you shouldn't copy this project "as is" for your own app: it would result in your app being
+identified in the consent screen as "gRPC-AuthSample", and not having access to real Google
+services. Instead, configure your own XCode project following the [instructions here](https://developers.google.com/identity/sign-in/ios/).
+
+As with the other examples, you also should have [Cocoapods](https://cocoapods.org/#install)
+installed, as well as the relevant tools to generate the client library code. You can obtain the
+latter by following [these setup instructions](https://github.com/grpc/homebrew-grpc).
+
+
+<a name="try"></a>
+## Try it out!
+
+To try the sample app, first have Cocoapods generate and install the client library for our .proto
+files:
+
+```shell
+$ pod install
+```
+
+(This might have to compile OpenSSL, which takes around 15 minutes if Cocoapods doesn't have it yet
+on your computer's cache).
+
+Finally, open the XCode workspace created by Cocoapods, and run the app.
+
+The first view, `SelectUserViewController.h/m`, asks you to sign in with your Google account, and to
+give the "gRPC-AuthSample" app the following permissions:
+
+- View your email address.
+- View your basic profile info.
+- "Test scope for access to the Zoo service".
+
+This last permission, corresponding to the scope `https://www.googleapis.com/auth/xapi.zoo` doesn't
+grant any real capability: it's only used for testing. You can log out at any time.
+
+The second view, `MakeRPCViewController.h/m`, makes a gRPC request to a test server at
+https://grpc-test.sandbox.google.com, sending the access token along with the request. The test
+service simply validates the token and writes in its response which user it belongs to, and which
+scopes it gives access to. (The client application already knows those two values; it's a way to
+verify that everything went as expected).
+
+The next sections guide you step-by-step through how the gRPC call in `MakeRPCViewController` is
+performed.
+
+<a name="rpc-object"></a>
+## Create an RPC object and start it later
+
+The other basic tutorials show how to invoke an RPC by calling an asynchronous method in a generated
+client object. This shows how to initialize an object that represents the RPC, and configure it
+before starting the network request.
+
+Assume you have a proto service definition like this:
+
+```protobuf
+option objc_class_prefix = "AUTH";
+
+service TestService {
+ rpc UnaryCall(Request) returns (Response);
+}
+```
+
+A `unaryCallWithRequest:handler:` method, with which you're already familiar, is generated for the
+`AUTHTestService` class:
+
+```objective-c
+[client unaryCallWithRequest:request handler:^(AUTHResponse *response, NSError *error) {
+ ...
+}];
+```
+
+In addition, an `RPCToUnaryCallWithRequest:handler:` method is generated, which returns a
+not-yet-started RPC object:
+
+```objective-c
+#import <ProtoRPC/ProtoRPC.h>
+
+ProtoRPC *call =
+ [client RPCToUnaryCallWithRequest:request handler:^(AUTHResponse *response, NSError *error) {
+ ...
+ }];
+```
+
+The RPC represented by this object can be started at any later time like this:
+
+```objective-c
+[call start];
+```
+
+<a name="request-metadata"></a>
+## Set request metadata of a call: Authorization header with an access token
+
+The `ProtoRPC` class has a `requestMetadata` property (inherited from `GRPCCall`) defined like this:
+
+```objective-c
+- (NSMutableDictionary *)requestMetadata; // nonatomic
+- (void)setRequestMetadata:(NSDictionary *)requestMetadata; // nonatomic, copy
+```
+
+Setting it to a dictionary of metadata keys and values will have them sent on the wire when the call
+is started. gRPC metadata are pieces of information about the call sent by the client to the server
+(and vice versa). They take the form of key-value pairs and are essentially opaque to gRPC itself.
+
+```objective-c
+call.requestMetadata = @{@"My-Header": @"Value for this header",
+ @"Another-Header": @"Its value"};
+```
+
+For convenience, the property is initialized with an empty `NSMutableDictionary`, so that request
+metadata elements can be set like this:
+
+```objective-c
+call.requestMetadata[@"My-Header"] = @"Value for this header";
+```
+
+If you have an access token, OAuth2 specifies it is to be sent in this format:
+
+```objective-c
+call.requestMetadata[@"Authorization"] = [@"Bearer " stringByAppendingString:accessToken];
+```
+
+<a name="response-metadata"></a>
+## Get response metadata of a call: Auth challenge header
+
+The `ProtoRPC` class also inherits a `responseMetadata` property, analogous to the request metadata
+we just looked at. It's defined like this:
+
+```objective-c
+@property(atomic, readonly) NSDictionary *responseMetadata;
+```
+
+To access OAuth2's authentication challenge header you write:
+
+```objective-c
+call.responseMetadata[@"www-authenticate"]
+```
+
+Note that, as gRPC metadata elements are mapped to HTTP/2 headers (or trailers), the keys of the
+response metadata are always ASCII strings in lowercase.
+
+Many uses cases of response metadata are getting more details about an RPC error. For convenience,
+when a `NSError` instance is passed to an RPC handler block, the response metadata dictionary can
+also be accessed this way:
+
+```objective-c
+error.userInfo[kGRPCStatusMetadataKey]
+```
diff --git a/examples/objective-c/auth_sample/SelectUserViewController.h b/examples/objective-c/auth_sample/SelectUserViewController.h
new file mode 100644
index 0000000000..eb3c2cf5f0
--- /dev/null
+++ b/examples/objective-c/auth_sample/SelectUserViewController.h
@@ -0,0 +1,42 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+#import <Google/SignIn.h>
+#import <UIKit/UIKit.h>
+
+@interface SelectUserViewController : UIViewController <GIDSignInDelegate, GIDSignInUIDelegate>
+@property(weak, nonatomic) IBOutlet GIDSignInButton *signInButton;
+@property(weak, nonatomic) IBOutlet UIButton *signOutButton;
+@property(weak, nonatomic) IBOutlet UILabel *mainLabel;
+@property(weak, nonatomic) IBOutlet UILabel *subLabel;
+@end
diff --git a/examples/objective-c/auth_sample/SelectUserViewController.m b/examples/objective-c/auth_sample/SelectUserViewController.m
new file mode 100644
index 0000000000..954c531f3f
--- /dev/null
+++ b/examples/objective-c/auth_sample/SelectUserViewController.m
@@ -0,0 +1,86 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+#import "SelectUserViewController.h"
+
+#import "MakeRPCViewController.h"
+
+@implementation SelectUserViewController
+
+- (void)viewDidLoad {
+ [super viewDidLoad];
+
+ self.signOutButton.layer.cornerRadius = 5;
+ self.signOutButton.hidden = YES;
+
+ // As instructed in https://developers.google.com/identity/sign-in/ios/sign-in
+ GIDSignIn *signIn = GIDSignIn.sharedInstance;
+ signIn.delegate = self;
+ signIn.uiDelegate = self;
+
+ // As instructed in https://developers.google.com/identity/sign-in/ios/additional-scopes
+ if (![signIn.scopes containsObject:kTestScope]) {
+ signIn.scopes = [signIn.scopes arrayByAddingObject:kTestScope];
+ }
+
+ [signIn signInSilently];
+}
+
+- (void)signIn:(GIDSignIn *)signIn
+didSignInForUser:(GIDGoogleUser *)user
+ withError:(NSError *)error {
+ if (error) {
+ // The user probably cancelled the sign-in flow.
+ return;
+ }
+
+ self.mainLabel.text = [NSString stringWithFormat:@"User: %@", user.profile.email];
+ NSString *scopes = [user.accessibleScopes componentsJoinedByString:@", "];
+ scopes = scopes.length ? scopes : @"(none)";
+ self.subLabel.text = [NSString stringWithFormat:@"Scopes: %@", scopes];
+
+ self.signInButton.hidden = YES;
+ self.signOutButton.hidden = NO;
+}
+
+- (IBAction)didTapSignOut {
+ [GIDSignIn.sharedInstance signOut];
+
+ self.mainLabel.text = @"Please sign in.";
+ self.subLabel.text = @"";
+
+ self.signInButton.hidden = NO;
+ self.signOutButton.hidden = YES;
+}
+
+@end