4 32.20.1. Authdata Hooks
5 32.20.2. Debugging and Developer Settings
7 libpq implements support for the OAuth v2 Device Authorization client
8 flow, documented in RFC 8628, as an optional module. See the
9 installation documentation for information on how to enable support for
10 Device Authorization as a builtin flow.
12 When support is enabled and the optional module installed, libpq will
13 use the builtin flow by default if the server requests a bearer token
14 during authentication. This flow can be utilized even if the system
15 running the client application does not have a usable web browser, for
16 example when running a client via SSH.
18 The builtin flow will, by default, print a URL to visit and a user code
20 $ psql 'dbname=postgres oauth_issuer=https://example.com oauth_client_id=...'
21 Visit https://example.com/device and enter the code: ABCD-EFGH
23 (This prompt may be customized.) The user will then log into their
24 OAuth provider, which will ask whether to allow libpq and the server to
25 perform actions on their behalf. It is always a good idea to carefully
26 review the URL and permissions displayed, to ensure they match
27 expectations, before continuing. Permissions should not be given to
28 untrusted third parties.
30 Client applications may implement their own flows to customize
31 interaction and integration with applications. See Section 32.20.1 for
32 more information on how add a custom flow to libpq.
34 For an OAuth client flow to be usable, the connection string must at
35 minimum contain oauth_issuer and oauth_client_id. (These settings are
36 determined by your organization's OAuth provider.) The builtin flow
37 additionally requires the OAuth authorization server to publish a
38 device authorization endpoint.
42 The builtin Device Authorization flow is not currently supported on
43 Windows. Custom client flows may still be implemented.
45 32.20.1. Authdata Hooks #
47 The behavior of the OAuth flow may be modified or replaced by a client
48 using the following hook API:
51 Sets the PGauthDataHook, overriding libpq's handling of one or
52 more aspects of its OAuth client flow.
54 void PQsetAuthDataHook(PQauthDataHook_type hook);
56 If hook is NULL, the default handler will be reinstalled.
57 Otherwise, the application passes a pointer to a callback
58 function with the signature:
60 int hook_fn(PGauthData type, PGconn *conn, void *data);
62 which libpq will call when an action is required of the
63 application. type describes the request being made, conn is the
64 connection handle being authenticated, and data points to
65 request-specific metadata. The contents of this pointer are
66 determined by type; see Section 32.20.1.1 for the supported
69 Hooks can be chained together to allow cooperative and/or
70 fallback behavior. In general, a hook implementation should
71 examine the incoming type (and, potentially, the request
72 metadata and/or the settings for the particular conn in use) to
73 decide whether or not to handle a specific piece of authdata. If
74 not, it should delegate to the previous hook in the chain
75 (retrievable via PQgetAuthDataHook).
77 Success is indicated by returning an integer greater than zero.
78 Returning a negative integer signals an error condition and
79 abandons the connection attempt. (A zero value is reserved for
80 the default implementation.)
83 Retrieves the current value of PGauthDataHook.
85 PQauthDataHook_type PQgetAuthDataHook(void);
87 At initialization time (before the first call to
88 PQsetAuthDataHook), this function will return
89 PQdefaultAuthDataHook.
91 32.20.1.1. Hook Types #
93 The following PGauthData types and their corresponding data structures
96 PQAUTHDATA_PROMPT_OAUTH_DEVICE #
97 Replaces the default user prompt during the builtin device
98 authorization client flow. data points to an instance of
101 typedef struct _PGpromptOAuthDevice
103 const char *verification_uri; /* verification URI to visit */
104 const char *user_code; /* user code to enter */
105 const char *verification_uri_complete; /* optional combination of URI and
107 int expires_in; /* seconds until user code expires */
108 } PGpromptOAuthDevice;
110 The OAuth Device Authorization flow which can be included in
111 libpq requires the end user to visit a URL with a browser, then
112 enter a code which permits libpq to connect to the server on
113 their behalf. The default prompt simply prints the
114 verification_uri and user_code on standard error. Replacement
115 implementations may display this information using any preferred
116 method, for example with a GUI.
118 This callback is only invoked during the builtin device
119 authorization flow. If the application installs a custom OAuth
120 flow, or libpq was not built with support for the builtin flow,
121 this authdata type will not be used.
123 If a non-NULL verification_uri_complete is provided, it may
124 optionally be used for non-textual verification (for example, by
125 displaying a QR code). The URL and user code should still be
126 displayed to the end user in this case, because the code will be
127 manually confirmed by the provider, and the URL lets users
128 continue even if they can't use the non-textual method. For more
129 information, see section 3.3.1 in RFC 8628.
131 PQAUTHDATA_OAUTH_BEARER_TOKEN #
132 Adds a custom implementation of a flow, replacing the builtin
133 flow if it is installed. The hook should either directly return
134 a Bearer token for the current user/issuer/scope combination, if
135 one is available without blocking, or else set up an
136 asynchronous callback to retrieve one.
138 data points to an instance of PGoauthBearerRequest, which should
139 be filled in by the implementation:
141 typedef struct PGoauthBearerRequest
143 /* Hook inputs (constant across all calls) */
144 const char *openid_configuration; /* OIDC discovery URL */
145 const char *scope; /* required scope(s), or NULL */
149 /* Callback implementing a custom asynchronous OAuth flow. */
150 PostgresPollingStatusType (*async) (PGconn *conn,
151 struct PGoauthBearerRequest *request,
154 /* Callback to clean up custom allocations. */
155 void (*cleanup) (PGconn *conn, struct PGoauthBearerRequest *request);
157 char *token; /* acquired Bearer token */
158 void *user; /* hook-defined allocated data */
159 } PGoauthBearerRequest;
161 Two pieces of information are provided to the hook by libpq:
162 openid_configuration contains the URL of an OAuth discovery
163 document describing the authorization server's supported flows,
164 and scope contains a (possibly empty) space-separated list of
165 OAuth scopes which are required to access the server. Either or
166 both may be NULL to indicate that the information was not
167 discoverable. (In this case, implementations may be able to
168 establish the requirements using some other preconfigured
169 knowledge, or they may choose to fail.)
171 The final output of the hook is token, which must point to a
172 valid Bearer token for use on the connection. (This token should
173 be issued by the oauth_issuer and hold the requested scopes, or
174 the connection will be rejected by the server's validator
175 module.) The allocated token string must remain valid until
176 libpq is finished connecting; the hook should set a cleanup
177 callback which will be called when libpq no longer requires it.
179 If an implementation cannot immediately produce a token during
180 the initial call to the hook, it should set the async callback
181 to handle nonblocking communication with the authorization
182 server. ^[16] This will be called to begin the flow immediately
183 upon return from the hook. When the callback cannot make further
184 progress without blocking, it should return either
185 PGRES_POLLING_READING or PGRES_POLLING_WRITING after setting
186 *pgsocket to the file descriptor that will be marked ready to
187 read/write when progress can be made again. (This descriptor is
188 then provided to the top-level polling loop via PQsocket().)
189 Return PGRES_POLLING_OK after setting token when the flow is
190 complete, or PGRES_POLLING_FAILED to indicate failure.
192 Implementations may wish to store additional data for
193 bookkeeping across calls to the async and cleanup callbacks. The
194 user pointer is provided for this purpose; libpq will not touch
195 its contents and the application may use it at its convenience.
196 (Remember to free any allocations during token cleanup.)
198 32.20.2. Debugging and Developer Settings #
200 A "dangerous debugging mode" may be enabled by setting the environment
201 variable PGOAUTHDEBUG=UNSAFE. This functionality is provided for ease
202 of local development and testing only. It does several things that you
203 will not want a production system to do:
204 * permits the use of unencrypted HTTP during the OAuth provider
206 * allows the system's trusted CA list to be completely replaced using
207 the PGOAUTHCAFILE environment variable
208 * prints HTTP traffic (containing several critical secrets) to
209 standard error during the OAuth flow
210 * permits the use of zero-second retry intervals, which can cause the
211 client to busy-loop and pointlessly consume CPU
215 Do not share the output of the OAuth flow traffic with third parties.
216 It contains secrets that can be used to attack your clients and
219 ^[16] Performing blocking operations during the
220 PQAUTHDATA_OAUTH_BEARER_TOKEN hook callback will interfere with
221 nonblocking connection APIs such as PQconnectPoll and prevent
222 concurrent connections from making progress. Applications which only
223 ever use the synchronous connection primitives, such as PQconnectdb,
224 may synchronously retrieve a token during the hook instead of
225 implementing the async callback, but they will necessarily be limited
226 to one connection at a time.