parent
98cbb3f198
commit
3508c9a5b8
1 changed files with 174 additions and 0 deletions
@ -0,0 +1,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. |
Loading…
Reference in new issue