README.md
1# Authentication Extension Example in gRPC Python
2
3## Check Our Guide First
4
5For most common usage of authentication in gRPC Python, please see our
6[Authentication](https://grpc.io/docs/guides/auth/) guide's Python section. The
7Guide includes following scenarios:
8
91. Server SSL credential setup
102. Client SSL credential setup
113. Authenticate with Google using a JWT
124. Authenticate with Google using an Oauth2 token
13
14Also, the guide talks about gRPC specific credential types.
15
16### Channel credentials
17
18Channel credentials are attached to a `Channel` object, the most common use case
19are SSL credentials.
20
21### Call credentials
22
23Call credentials are attached to a `Call` object (corresponding to an RPC).
24Under the hood, the call credentials is a function that takes in information of
25the RPC and modify metadata through callback.
26
27## About This Example
28
29This example focuses on extending gRPC authentication mechanism:
301) Customize authentication plugin;
312) Composite client side credentials;
323) Validation through interceptor on server side.
33
34## AuthMetadataPlugin: Manipulate metadata for each call
35
36Unlike TLS/SSL based authentication, the authentication extension in gRPC Python
37lives at a much higher level of networking. It relies on the transmission of
38metadata (HTTP Header) between client and server, instead of alternating the
39transport protocol.
40
41gRPC Python provides a way to intercept an RPC and append authentication related
42metadata through
43[`AuthMetadataPlugin`](https://grpc.github.io/grpc/python/grpc.html#grpc.AuthMetadataPlugin).
44Those in need of a custom authentication method may simply provide a concrete
45implementation of the following interface:
46
47```Python
48class AuthMetadataPlugin:
49 """A specification for custom authentication."""
50
51 def __call__(self, context, callback):
52 """Implements authentication by passing metadata to a callback.
53
54 Implementations of this method must not block.
55
56 Args:
57 context: An AuthMetadataContext providing information on the RPC that
58 the plugin is being called to authenticate.
59 callback: An AuthMetadataPluginCallback to be invoked either
60 synchronously or asynchronously.
61 """
62```
63
64Then pass the instance of the concrete implementation to
65`grpc.metadata_call_credentials` function to be converted into a
66`CallCredentials` object. Please NOTE that it is possible to pass a Python
67function object directly, but we recommend to inherit from the base class to
68ensure implementation correctness.
69
70
71```Python
72def metadata_call_credentials(metadata_plugin, name=None):
73 """Construct CallCredentials from an AuthMetadataPlugin.
74
75 Args:
76 metadata_plugin: An AuthMetadataPlugin to use for authentication.
77 name: An optional name for the plugin.
78
79 Returns:
80 A CallCredentials.
81 """
82```
83
84The `CallCredentials` object can be passed directly into an RPC like:
85
86```Python
87call_credentials = grpc.metadata_call_credentials(my_foo_plugin)
88stub.FooRpc(request, credentials=call_credentials)
89```
90
91Or you can use `ChannelCredentials` and `CallCredentials` at the same time by
92combining them:
93
94```Python
95channel_credentials = ...
96call_credentials = ...
97composite_credentials = grpc.composite_channel_credentials(
98 channel_credential,
99 call_credentials)
100channel = grpc.secure_channel(server_address, composite_credentials)
101```
102
103It is also possible to apply multiple `CallCredentials` to a single RPC:
104
105```Python
106call_credentials_foo = ...
107call_credentials_bar = ...
108call_credentials = grpc.composite_call_credentials(
109 call_credentials_foo,
110 call_credentials_bar)
111stub.FooRpc(request, credentials=call_credentials)
112```
113
114## Token-based authentication
115
116Instead of `AuthMetadataPlugin`, you can also use token-based authentication
117mechanisms using OAuth2 tokens or other customized tokens.
118
119OAuth2 tokens can be obtained using libraries like [google-auth](https://google-auth.readthedocs.io/en/master/user-guide.html):
120
121```Python
122import google.auth
123
124google_credentials, unused_project_id = google.auth.default()
125call_credentials = grpc.access_token_call_credentials(google_credentials.token)
126```
127
128After obtaining the token, the rest of the flow is documented in [token_based_auth_client.py](https://github.com/grpc/grpc/tree/master/examples/python/auth/token_based_auth_client.py) and [token_based_auth_server.py](https://github.com/grpc/grpc/tree/master/examples/python/auth/token_based_auth_server.py).
129