mirror of https://github.com/grpc/grpc.io.git
342 lines
20 KiB
HTML
342 lines
20 KiB
HTML
|
|
|
|
<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
|
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous">
|
|
<link href="https://fonts.googleapis.com/css?family=Open+Sans:300,400" rel="stylesheet">
|
|
<link rel="stylesheet" type="text/css" href="/css/style.css">
|
|
<title>
|
|
OAuth2 on gRPC - Objective-C – gRPC
|
|
</title>
|
|
|
|
|
|
<link rel="apple-touch-icon" href="/favicons/apple-touch-icon.png" sizes="180x180">
|
|
<link rel="icon" type="image/png" href="/favicons/android-chrome-192x192.png" sizes="192x192" >
|
|
<link rel="icon" type="image/png" href="/favicons/favicon-32x32.png" sizes="32x32">
|
|
<link rel="icon" type="image/png" href="/favicons/favicon-16x16.png" sizes="16x16">
|
|
<link rel="manifest" href="/favicons/manifest.json">
|
|
<link rel="mask-icon" href="/favicons/safari-pinned-tab.svg" color="#2DA6B0">
|
|
<meta name="msapplication-TileColor" content="#ffffff">
|
|
<meta name="msapplication-TileImage" content="/favicons/mstile-150x150.png">
|
|
|
|
|
|
<script async src="https://www.googletagmanager.com/gtag/js?id=UA-60127042-1"></script>
|
|
<script>
|
|
window.dataLayer = window.dataLayer || [];
|
|
function gtag(){dataLayer.push(arguments);}
|
|
gtag('js', new Date());
|
|
|
|
gtag('config', 'UA-60127042-1');
|
|
</script>
|
|
|
|
</head>
|
|
<body>
|
|
<div id="landing-content">
|
|
<div class="row">
|
|
<div class="topbannersub">
|
|
<nav class="navbar navbar-expand-md navbar-dark topnav">
|
|
<a class="navbar-brand" href="https://cjyabraham.github.io/">
|
|
<img src="https://cjyabraham.github.io/img/grpc-logo.png" width="114" height="50">
|
|
</a>
|
|
|
|
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
|
|
<span class="navbar-toggler-icon"></span>
|
|
</button>
|
|
|
|
<div class="topnav, collapse navbar-collapse" id="navbarSupportedContent" style="float:right !important">
|
|
<ul class="navbar-nav ml-auto">
|
|
<li class="nav-item ">
|
|
<a class="nav-link" href="https://cjyabraham.github.io/about/">About</a>
|
|
</li>
|
|
<li class="nav-item dropdown active">
|
|
<a class="nav-link dropdown-toggle" href="https://cjyabraham.github.io/docs/" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
|
Docs
|
|
</a>
|
|
|
|
<div class="dropdown-menu" aria-labelledby="navbarDropdown">
|
|
|
|
|
|
<a class="dropdown-item" href="/docs">
|
|
Overview
|
|
</a>
|
|
|
|
|
|
<a class="dropdown-item" href="/docs/quickstart/">
|
|
Quick Start
|
|
</a>
|
|
|
|
|
|
<a class="dropdown-item" href="/docs/guides/">
|
|
Guides
|
|
</a>
|
|
|
|
|
|
<a class="dropdown-item" href="/docs/tutorials/">
|
|
Tutorials
|
|
</a>
|
|
|
|
|
|
<a class="dropdown-item" href="/docs/reference/">
|
|
Reference
|
|
</a>
|
|
|
|
|
|
<a class="dropdown-item" href="/docs/samples/">
|
|
Samples
|
|
</a>
|
|
|
|
|
|
<a class="dropdown-item" href="/docs/talks">
|
|
Presentations
|
|
</a>
|
|
|
|
</div>
|
|
</li>
|
|
<li class="nav-item ">
|
|
<a class="nav-link" href="/blog">
|
|
Blog
|
|
</a>
|
|
</li>
|
|
<li class="nav-item ">
|
|
<a class="nav-link" href="/community">Community</a>
|
|
</li>
|
|
<li class="nav-item">
|
|
<a class="nav-link" href="https://packages.grpc.io/">
|
|
Packages
|
|
</a>
|
|
</li>
|
|
<li class="nav-item ">
|
|
<a class="nav-link" href="https://cjyabraham.github.io/faq/">FAQ</a>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
</nav>
|
|
|
|
|
|
<div class="headertext">Documentation</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="subnav d-none d-md-block">
|
|
<a href="https://cjyabraham.github.io/docs/" >Overview</a>
|
|
| <a href="https://cjyabraham.github.io/docs/quickstart/" >Quick Start</a>
|
|
| <a href="https://cjyabraham.github.io/docs/guides/" >Guides</a>
|
|
| <a href="https://cjyabraham.github.io/docs/tutorials/" class="active">Tutorials</a>
|
|
| <a href="https://cjyabraham.github.io/docs/reference/" >Reference</a>
|
|
| <a href="https://cjyabraham.github.io/docs/samples/" >Samples</a>
|
|
| <a href="https://cjyabraham.github.io/docs/talks/" >Presentations</a>
|
|
</div>
|
|
|
|
|
|
<div class="quickstartcols">
|
|
|
|
<div class="quickstartcol1">
|
|
|
|
<h8>Tutorials</h8>
|
|
<a href="https://cjyabraham.github.io/docs/tutorials/async/helloasync-cpp/" >Async - C++</a>
|
|
<a href="https://cjyabraham.github.io/docs/tutorials/auth/oauth2-objective-c/" class="active">Auth - Objective C</a>
|
|
<h8>Basic</h8>
|
|
<a href="https://cjyabraham.github.io/docs/tutorials/basic/c/" >C++</a>
|
|
<a href="https://cjyabraham.github.io/docs/tutorials/basic/csharp/" >C#</a>
|
|
<a href="https://cjyabraham.github.io/docs/tutorials/basic/dart/" >Dart</a>
|
|
<a href="https://cjyabraham.github.io/docs/tutorials/basic/go/" >Go</a>
|
|
<a href="https://cjyabraham.github.io/docs/tutorials/basic/java/" >Java</a>
|
|
<a href="https://cjyabraham.github.io/docs/tutorials/basic/android/" >Android Java</a>
|
|
<a href="https://cjyabraham.github.io/docs/tutorials/basic/node/" >Node</a>
|
|
<a href="https://cjyabraham.github.io/docs/tutorials/basic/objective-c/" class="active">Objective-C</a>
|
|
<a href="https://cjyabraham.github.io/docs/tutorials/basic/php/" >PHP</a>
|
|
<a href="https://cjyabraham.github.io/docs/tutorials/basic/python/" >Python</a>
|
|
<a href="https://cjyabraham.github.io/docs/tutorials/basic/ruby/" >Ruby</a>
|
|
<a href="https://cjyabraham.github.io/docs/tutorials/basic/web/" >Web</a>
|
|
|
|
</div>
|
|
|
|
<div class="quickstartcol2" style="margin-top:4%">
|
|
<h3 style="margin-top:0px;">OAuth2 on gRPC - Objective-C</h3>
|
|
|
|
|
|
|
|
<p>This example demonstrates how to use OAuth2 on gRPC to make
|
|
authenticated API calls on behalf of a user.</p>
|
|
|
|
<p>By walking through it you’ll also learn how to use the Objective-C gRPC API to:</p>
|
|
|
|
<ul>
|
|
<li>Initialize and configure a remote call object before the RPC is started.</li>
|
|
<li>Set request metadata elements on a call, which are semantically equivalent to
|
|
HTTP request headers.</li>
|
|
<li>Read response metadata from a call, which is equivalent to HTTP response
|
|
headers and trailers.</li>
|
|
</ul>
|
|
|
|
<p>It assumes you know the basics on how to make gRPC API calls using the
|
|
Objective-C client library, as shown in <a href="/docs/tutorials/basic/objective-c/">gRPC Basics:
|
|
Objective-C</a> and the
|
|
<a href="/docs/">overview</a>, and are familiar with OAuth2 concepts like <em>access
|
|
token</em>.</p>
|
|
|
|
<div id="toc"></div>
|
|
|
|
<p><a name="setup"></a></p>
|
|
|
|
<h3 id="example-code-and-setup">Example code and setup</h3>
|
|
|
|
<p>The example code for our tutorial is in
|
|
<a href="https://github.com/grpc/grpc/tree/
|
|
v1.20.0/examples/objective-c/auth_sample">gprc/examples/objective-c/auth_sample</a>. To
|
|
download the example, clone this repository by running the following commands:</p>
|
|
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-sh" data-lang="sh">$ git clone -b v1.20.0 https://github.com/grpc/grpc
|
|
$ cd grpc
|
|
$ git submodule update --init</code></pre></div>
|
|
<p>Then change your current directory to <code>examples/objective-c/auth_sample</code>:</p>
|
|
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-sh" data-lang="sh">$ cd examples/objective-c/auth_sample</code></pre></div>
|
|
<p>Our example is a simple application with two views. The first view lets a user
|
|
sign in and out using the OAuth2 flow of Google’s <a href="https://developers.google.com/identity/sign-in/ios/">iOS SignIn
|
|
library</a>. (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.</p>
|
|
|
|
<p>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 <a href="https://developers.google.com/identity/sign-in/ios/">instructions
|
|
here</a>.</p>
|
|
|
|
<p>As with the other Objective-C examples, you also should have
|
|
<a href="https://cocoapods.org/#install">Cocoapods</a> installed, as well as the relevant
|
|
tools to generate the client library code. You can obtain the latter by
|
|
following <a href="https://github.com/grpc/homebrew-grpc">these setup instructions</a>.</p>
|
|
|
|
<p><a name="try"></a></p>
|
|
|
|
<h3 id="try-it-out">Try it out!</h3>
|
|
|
|
<p>To try the sample app, first have Cocoapods generate and install the client library for our .proto
|
|
files:</p>
|
|
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-sh" data-lang="sh">$ pod install</code></pre></div>
|
|
<p>(This might have to compile OpenSSL, which takes around 15 minutes if Cocoapods
|
|
doesn’t have it yet on your computer’s cache).</p>
|
|
|
|
<p>Finally, open the XCode workspace created by Cocoapods, and run the app.</p>
|
|
|
|
<p>The first view, <code>SelectUserViewController.h/m</code>, asks you to sign in with your
|
|
Google account, and to give the “gRPC-AuthSample” app the following permissions:</p>
|
|
|
|
<ul>
|
|
<li>View your email address.</li>
|
|
<li>View your basic profile info.</li>
|
|
<li>“Test scope for access to the Zoo service”.</li>
|
|
</ul>
|
|
|
|
<p>This last permission, corresponding to the scope
|
|
<code>https://www.googleapis.com/auth/xapi.zoo</code> doesn’t grant any real capability:
|
|
it’s only used for testing. You can log out at any time.</p>
|
|
|
|
<p>The second view, <code>MakeRPCViewController.h/m</code>, makes a gRPC request to a test
|
|
server at <a href="https://grpc-test.sandbox.google.com">https://grpc-test.sandbox.google.com</a>, 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).</p>
|
|
|
|
<p>The next sections guide you step-by-step through how the gRPC call in
|
|
<code>MakeRPCViewController</code> is performed. You can see the complete code in
|
|
<a href="https://github.com/grpc/grpc/blob/v1.20.0/examples/objective-c/auth_sample/MakeRPCViewController.m">MakeRPCViewController.m</a>.</p>
|
|
|
|
<p><a name="rpc-object"></a></p>
|
|
|
|
<h3 id="create-an-rpc-object">Create an RPC object</h3>
|
|
|
|
<p>The other basic tutorials show how to invoke an RPC by calling an asynchronous
|
|
method in a generated client object. However, to make an authenticated call you
|
|
need to initialize an object that represents the RPC, and configure it <em>before</em>
|
|
starting the network request. First let’s look at how to create the RPC object.</p>
|
|
|
|
<p>Assume you have a proto service definition like this:</p>
|
|
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-protobuf" data-lang="protobuf"><span style="color:#66d9ef">option</span> objc_class_prefix <span style="color:#f92672">=</span> <span style="color:#e6db74">"AUTH"</span>;<span style="color:#960050;background-color:#1e0010">
|
|
</span><span style="color:#960050;background-color:#1e0010">
|
|
</span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">service</span> TestService {<span style="color:#960050;background-color:#1e0010">
|
|
</span><span style="color:#960050;background-color:#1e0010"></span> <span style="color:#66d9ef">rpc</span> UnaryCall(Request) <span style="color:#66d9ef">returns</span> (Response);<span style="color:#960050;background-color:#1e0010">
|
|
</span><span style="color:#960050;background-color:#1e0010"></span>}</code></pre></div>
|
|
<p>A <code>unaryCallWithRequest:handler:</code> method, with which you’re already familiar, is
|
|
generated for the <code>AUTHTestService</code> class:</p>
|
|
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-objective-c" data-lang="objective-c">[client unaryCallWithRequest:request handler:<span style="color:#f92672">^</span>(AUTHResponse <span style="color:#f92672">*</span>response, NSError <span style="color:#f92672">*</span>error) {
|
|
...
|
|
}];</code></pre></div>
|
|
<p>In addition, an <code>RPCToUnaryCallWithRequest:handler:</code> method is generated, which returns a
|
|
not-yet-started RPC object:</p>
|
|
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-objective-c" data-lang="objective-c"><span style="color:#75715e">#import <ProtoRPC/ProtoRPC.h>
|
|
</span><span style="color:#75715e"></span>
|
|
ProtoRPC <span style="color:#f92672">*</span>call <span style="color:#f92672">=</span>
|
|
[client RPCToUnaryCallWithRequest:request handler:<span style="color:#f92672">^</span>(AUTHResponse <span style="color:#f92672">*</span>response, NSError <span style="color:#f92672">*</span>error) {
|
|
...
|
|
}];</code></pre></div>
|
|
<p>You can start the RPC represented by this object at any later time like this:</p>
|
|
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-objective-c" data-lang="objective-c">[call start];</code></pre></div>
|
|
<p><a name="request-metadata"></a></p>
|
|
|
|
<h3 id="setting-request-metadata-auth-header-with-an-access-token">Setting request metadata: Auth header with an access token</h3>
|
|
|
|
<p>Now let’s look at how to configure some settings on the RPC object. The
|
|
<code>ProtoRPC</code> class has a <code>requestHeaders</code> property (inherited from <code>GRPCCall</code>)
|
|
defined like this:</p>
|
|
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-objective-c" data-lang="objective-c"><span style="color:#66d9ef">@property</span>(<span style="color:#66d9ef">atomic</span>, <span style="color:#66d9ef">readonly</span>) <span style="color:#66d9ef">id</span><span style="color:#f92672"><</span>GRPCRequestHeaders<span style="color:#f92672">></span> requestHeaders</code></pre></div>
|
|
<p>You can think of the <code>GRPCRequestHeaders</code> protocol as equivalent to the
|
|
<code>NSMutableDictionary</code> class. Setting elements of this dictionary of metadata
|
|
keys and values means this metadata will be 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.</p>
|
|
|
|
<p>For convenience, the property is initialized with an empty
|
|
<code>NSMutableDictionary</code>, so that request metadata elements can be set like this:</p>
|
|
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-objective-c" data-lang="objective-c">call.requestHeaders[<span style="color:#e6db74">@"My-Header"</span>] <span style="color:#f92672">=</span> <span style="color:#e6db74">@"Value for this header"</span>;
|
|
call.requestHeaders[<span style="color:#e6db74">@"Another-Header"</span>] <span style="color:#f92672">=</span> <span style="color:#e6db74">@"Its value"</span>;</code></pre></div>
|
|
<p>A typical use of metadata is for authentication details, as in our example. If
|
|
you have an access token, OAuth2 specifies it is to be sent in this format:</p>
|
|
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-objective-c" data-lang="objective-c">call.requestHeaders[<span style="color:#e6db74">@"Authorization"</span>] <span style="color:#f92672">=</span> [<span style="color:#e6db74">@"Bearer "</span> stringByAppendingString:accessToken];</code></pre></div>
|
|
<p><a name="response-metadata"></a></p>
|
|
|
|
<h3 id="getting-response-metadata-auth-challenge-header">Getting response metadata: Auth challenge header</h3>
|
|
|
|
<p>The <code>ProtoRPC</code> class also inherits a pair of properties, <code>responseHeaders</code> and
|
|
<code>responseTrailers</code>, analogous to the request metadata we just looked at but sent
|
|
back by the server to the client. They are defined like this:</p>
|
|
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-objective-c" data-lang="objective-c"><span style="color:#66d9ef">@property</span>(<span style="color:#66d9ef">atomic</span>, <span style="color:#66d9ef">readonly</span>) NSDictionary <span style="color:#f92672">*</span>responseHeaders;
|
|
<span style="color:#66d9ef">@property</span>(<span style="color:#66d9ef">atomic</span>, <span style="color:#66d9ef">readonly</span>) NSDictionary <span style="color:#f92672">*</span>responseTrailers;</code></pre></div>
|
|
<p>In OAuth2, if there’s an authentication error the server will send back a
|
|
challenge header. This is returned in the RPC’s response headers. To access
|
|
this, as in our example’s error-handling code, you write:</p>
|
|
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-objective-c" data-lang="objective-c">call.responseHeaders[<span style="color:#e6db74">@"www-authenticate"</span>]</code></pre></div>
|
|
<p>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.</p>
|
|
|
|
<p>Many uses cases of response metadata involve getting more details about an RPC
|
|
error. For convenience, when a <code>NSError</code> instance is passed to an RPC handler
|
|
block, the response headers and trailers dictionaries can also be accessed this
|
|
way:</p>
|
|
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-objective-c" data-lang="objective-c">error.userInfo[kGRPCHeadersKey] <span style="color:#f92672">==</span> call.responseHeaders
|
|
error.userInfo[kGRPCTrailersKey] <span style="color:#f92672">==</span> call.responseTrailers</code></pre></div>
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
|
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.3/umd/popper.min.js" integrity="sha384-ZMP7rVo3mIykV+2+9J3UJ46jBk0WLaUAdn689aCwoqbBJiSnjAK/l8WvCWPIPm49" crossorigin="anonymous"></script>
|
|
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/js/bootstrap.min.js" integrity="sha384-ChfqqxuZUCnJSK3+MXmPNIyE6ZbWh2IMqE241rYiqJxyMiZ6OW/JmZQ5stwEULTy" crossorigin="anonymous"></script>
|
|
|
|
</body>
|
|
</html>
|