1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
|
#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](https://github.com/grpc/grpc-common/tree/master/objective-c/helloworld)
or [Route Guide](https://github.com/grpc/grpc-common/tree/master/objective-c/route_guide) tutorials,
and familiarity 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 [grpc/grpc-common/objective-c/auth_sample](https://github.com/grpc/grpc-common/tree/master/objective-c/auth_sample).
To download the example, clone the `grpc-common` repository by running the following command:
```shell
$ git clone https://github.com/grpc/grpc-common.git
```
Then change your current directory to `grpc-common/objective-c/auth_sample`:
```shell
$ cd grpc-common/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 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 moment.
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 is generated, with which you're already familiar, is
generated for the `AUTHTestService` class:
```objective-c
[client unaryCallWithRequest:request handler:^(AUTHResponse *response, NSError *error) {
...
}];
```
And a second `RPCToUnaryCallWithRequest:handler:` method is generated, which returns a
not-yet-started RPC object:
```objective-c
#import <gRPC/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 defined like this:
```objective-c
@property(nonatomic, readwrite) NSMutableDictionary *requestMetadata;
```
Setting it to a dictionary of metadata keys and values will have them sent on the wire when the call
is started.
```objective-c
call.requestMetadata = [NSMutableDictionary dictionaryWithDictionary:
@{@"My-Header": @"Value for this header",
@"Another-Header": @"Its value"}];
```
If you have an access token, OAuth2 specifies it is to be sent in this format:
```objective-c
@{@"Authorization": [@"Bearer " stringByAppendingString:accessToken]}
```
<a name="response-metadata"></a>
## Get response metadata of a call: Auth challenge header
Analogously to the request metadata, the `ProtoRPC` class has a `responseMetadata` property defined
this way:
```objective-c
@property(atomic, readonly) NSDictionary *responseMetadata;
```
Because gRPC metadata keys can be repeated, the values of the `responseMetadata` dictionary are
always `NSArray`s. Thus, to access OAuth2's authentication challenge header you write:
```objective-c
call.responseMetadata[@"www-authenticate"][0]
```
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.
|