@@ -925,7 +925,7 @@ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
925925> **Note:**
926926>
927927> If we wanted to query the scheduler instead of the device, we would look
928- > up the "printer-uri-supported" option instead of the "device-uri" value .
928+ > up the "printer-uri-supported" option instead of the "device-uri" option .
929929
930930The [`ippAddString`](@@) function adds the "printer-uri" attribute the the IPP
931931request. The `IPP_TAG_OPERATION` argument specifies that the attribute is part
@@ -947,15 +947,15 @@ static const char * const requested_attributes[] =
947947};
948948
949949ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
950- "requested-attributes", 3, NULL,
950+ "requested-attributes", /*num_values*/ 3, /*language*/ NULL,
951951 requested_attributes);
952952` ` `
953953
954954The [`ippAddStrings`](@@) function adds an attribute with one or more strings,
955955in this case three. The `IPP_TAG_KEYWORD` argument specifies that the strings
956956are keyword values, which are used for attribute names. All strings use the
957- same language (`NULL`), and the attribute will contain the three strings in the
958- array `requested_attributes`.
957+ same language (`NULL`), and the attribute will contain the three strings from
958+ the array `requested_attributes`.
959959
960960CUPS provides many functions to adding attributes of different types :
961961
@@ -1106,18 +1106,32 @@ Once you are done using the IPP response message, free it using the
11061106 ippDelete(response);
11071107
11081108
1109- # # Authentication
1109+ # Authentication and Authorization
11101110
1111- CUPS normally handles authentication through the console. GUI applications
1112- should set a password callback using the [`cupsSetPasswordCB`](@@) function :
1111+ CUPS supports authentication and authorization using HTTP Basic, HTTP Digest,
1112+ peer credentials when communicating over domain sockets, and OAuth/OpenID
1113+ Connect.
1114+
1115+ Peer credential authorization happens automatically when connected over a
1116+ domain socket. Other types of authentication requires the application to
1117+ handle `HTTP_STATUS_UNAUTHORIZED` responses beyond simply calling
1118+ [`cupsDoAuthentication`](@@).
1119+
1120+
1121+ # # Authentication Using Passwords
1122+
1123+ When you call [`cupsDoAuthentication`](@@), CUPS normally requests a password
1124+ from the console. GUI applications should set a password callback using the
1125+ [`cupsSetPasswordCB`](@@) function :
11131126
11141127` ` ` c
11151128void
11161129cupsSetPasswordCB(cups_password_cb_t cb, void *cb_data);
11171130` ` `
11181131
1119- The password callback will be called when needed and is responsible for setting
1120- the current user name using [`cupsSetUser`](@@) and returning a string :
1132+ The password callback is called when needed and is responsible for setting
1133+ the current user name using [`cupsSetUser`](@@) and returning a (password)
1134+ string :
11211135
11221136` ` ` c
11231137const char *
@@ -1143,6 +1157,189 @@ The "cb_data" argument provides the user data pointer from the
11431157[`cupsSetPasswordCB`](@@) call.
11441158
11451159
1160+ # # Authorization using OAuth/OpenID Connect
1161+
1162+ CUPS provides a generic OAuth/OpenID client for authorizing access to printers
1163+ and other network resources. The following functions are provided :
1164+
1165+ - [`cupsOAuthClearTokens`](@@) : Clear all cached tokens.
1166+ - [`cupsOAuthCopyAccessToken`](@@) : Copy the cached access token.
1167+ - [`cupsOAuthCopyClientId`](@@) : Copy the cached client ID.
1168+ - [`cupsOAuthCopyRefreshToken`](@@) : Copy the cached refresh token.
1169+ - [`cupsOAuthCopyUserId`](@@) : Copy the cached user ID.
1170+ - [`cupsOAuthGetAuthorizationCode`](@@) : Get an authorization code using a web
1171+ browser.
1172+ - [`cupsOAuthGetClientId`](@@) : Get a client ID using dynamic client
1173+ registration.
1174+ - [`cupsOAuthGetDeviceGrant`](@@) : Get a device authorization grant code.
1175+ - [`cupsOAuthGetJWKS`](@@) : Get the key set for an authorization server.
1176+ - [`cupsOAuthGetMetadata`](@@) : Get the metadata for an authorization server.
1177+ - [`cupsOAuthGetTokens`](@@) : Get access and refresh tokens for an
1178+ authorization/grant code.
1179+ - [`cupsOAuthGetUserId`](@@) : Get the user ID associated with an access token.
1180+ - [`cupsOAuthMakeAuthorizationURL`](@@) : Make the URL for web browser
1181+ authorization.
1182+ - [`cupsOAuthMakeBase64Random`](@@) : Make a Base64-encoded string of random
1183+ bytes.
1184+ - [`cupsOAuthSaveClientData`](@@) : Save a client ID and secret for an
1185+ authorization server.
1186+ - [`cupsOAuthSaveTokens`](@@) : Save access and refresh tokens for an
1187+ authorization server.
1188+
1189+ Once you have an access token you use the [`httpSetAuthString`](@@) function to
1190+ use it for a HTTP connection :
1191+
1192+ ` ` ` c
1193+ http_t *http;
1194+ char *access_token;
1195+
1196+ httpSetAuthString(http, "Bearer", access_token);
1197+ ` ` `
1198+
1199+
1200+ # ## Authorizing Using a Web Browser
1201+
1202+ Users can authorize using their preferred web browser via the
1203+ [`cupsOAuthGetAuthorizationCode`](@@) function, which returns an authorization
1204+ grant code string. The following code gets the authorization server metadata,
1205+ authorizes access through the web browser, and then obtains a HTTP Bearer access
1206+ token :
1207+
1208+ ` ` ` c
1209+ http_t *http; // HTTP connection
1210+ const char *auth_uri; // Base URL for Authorization Server
1211+ cups_json_t *metadata; // Authorization Server metadata
1212+ const char *printer_uri; // Printer URI
1213+ char *auth_code; // Authorization grant code
1214+ char *access_token; // Access token
1215+ time_t access_expires; // Date/time when access token expires
1216+
1217+ // Get the metadata for the authorization server.
1218+ metadata = cupsOAuthGetMetadata(auth_uri);
1219+
1220+ if (metadata == NULL)
1221+ {
1222+ // Handle error getting metadata from authorization server.
1223+ }
1224+
1225+ // Bring up the web browser to authorize and get an authorization code.
1226+ auth_code = cupsOAuthGetAuthorizationCode(auth_uri, metadata, printer_uri,
1227+ /*scopes*/NULL,
1228+ /*redirect_uri*/NULL);
1229+
1230+ if (auth_code == NULL)
1231+ {
1232+ // Unable to authorize.
1233+ }
1234+
1235+ // Get the access code from the authorization code.
1236+ access_token = cupsOAuthGetTokens(auth_uri, metadata, printer_uri, auth_code,
1237+ CUPS_OGRANT_AUTHORIZATION_CODE,
1238+ /*redirect_uri*/NULL, &access_expires);
1239+
1240+ if (access_token == NULL)
1241+ {
1242+ // Unable to get access token.
1243+ }
1244+
1245+ // Set the Bearer token for authorization.
1246+ httpSetAuthString(http, "Bearer", access_token);
1247+ ` ` `
1248+
1249+
1250+ # ## Authorizing Using a Mobile Device
1251+
1252+ Users can authorize using a mobile device via the
1253+ [`cupsOAuthGetDeviceGrant`](@@) function, which returns a JSON object with the
1254+ mobile authorization URLs, user (verification) code string, and device grant
1255+ code. The following code gets the authorization server metadata, gets the
1256+ mobile device authorization information, and then obtains a HTTP Bearer access
1257+ token :
1258+
1259+ ` ` ` c
1260+ http_t *http; // HTTP connection
1261+ const char *auth_uri; // Base URL for Authorization Server
1262+ cups_json_t *metadata; // Authorization Server metadata
1263+ const char *printer_uri; // Printer URI
1264+ cups_json_t *device_grant; // Device authorization grant object
1265+ const char *device_code; // Device grant code
1266+ const char *verify_url; // Mobile device URL
1267+ const char *verify_urlc; // Mobile device URL with user code
1268+ const char *user_code; // User code
1269+ char *access_token; // Access token
1270+ time_t access_expires; // Date/time when access token expires
1271+
1272+ // Get the metadata for the authorization server.
1273+ metadata = cupsOAuthGetMetadata(auth_uri);
1274+
1275+ if (metadata == NULL)
1276+ {
1277+ // Handle error getting metadata from authorization server.
1278+ }
1279+
1280+ // Get a device authorization grant for mobile authorization.
1281+ device_grant = cupsOAuthGetDeviceGrant(auth_uri, metadata, printer_uri,
1282+ /*scopes*/NULL);
1283+
1284+ device_code = cupsJSONGetString(
1285+ cupsJSONFind(device_grant, CUPS_ODEVGRANT_DEVICE_CODE));
1286+ verify_url = cupsJSONGetString(
1287+ cupsJSONFind(device_grant, CUPS_ODEVGRANT_VERIFICATION_URI));
1288+ verify_urlc = cupsJSONGetString(
1289+ cupsJSONFind(device_grant, CUPS_ODEVGRANT_VERIFICATION_URI_COMPLETE));
1290+ user_code = cupsJSONGetString(
1291+ cupsJSONFind(device_grant, CUPS_ODEVGRANT_USER_CODE));
1292+
1293+ if (device_code == NULL || verify_url == NULL || verify_urlc == NULL ||
1294+ user_code == NULL)
1295+ {
1296+ // Unable to authorize.
1297+ }
1298+
1299+ // Show the URLs and user code to the user (links and/or QR codes).
1300+ printf("Open this URL: %s\n ", verify_urlc);
1301+
1302+ // Get the access code from the authorization code.
1303+ do
1304+ {
1305+ // Delay check for several seconds.
1306+ sleep(5);
1307+
1308+ // Try getting an access token.
1309+ access_token = cupsOAuthGetTokens(auth_uri, metadata, printer_uri, device_code,
1310+ CUPS_OGRANT_DEVICE_CODE,
1311+ /*redirect_uri*/NULL, &access_expires);
1312+ }
1313+ while (access_token == NULL && access_expires > 0);
1314+ // Continue checking until we have an access token or
1315+ // the device code has expired.
1316+
1317+ if (access_token == NULL)
1318+ {
1319+ // Unable to get access token.
1320+ }
1321+
1322+ // Set the Bearer token for authorization.
1323+ httpSetAuthString(http, "Bearer", access_token);
1324+ ` ` `
1325+
1326+
1327+ # ## Supported OAuth Standards
1328+
1329+ The following standards are supported :
1330+
1331+ - [OpenID Connect Core v1.0](https://openid.net/specs/openid-connect-core-1_0.html)
1332+ - [RFC 6749 : The OAuth 2.0 Authorization Framework](https://datatracker.ietf.org/doc/html/rfc6749)
1333+ - [RFC 6750 : The OAuth 2.0 Authorization Framework: Bearer Token Usage](https://datatracker.ietf.org/doc/html/rfc6750)
1334+ - [RFC 7591 : OAuth 2.0 Dynamic Client Registration Protocol](https://datatracker.ietf.org/doc/html/rfc7591)
1335+ - [RFC 7636 : Proof Key for Code Exchange by OAuth Public Clients](https://datatracker.ietf.org/doc/html/rfc7636)
1336+ - [RFC 8252 : OAuth 2.0 for Native Apps](https://datatracker.ietf.org/doc/html/rfc8252)
1337+ - [RFC 8414 : OAuth 2.0 Authorization Server Metadata](https://datatracker.ietf.org/doc/html/rfc8414)
1338+ - [RFC 8628 : OAuth 2.0 Device Authorization Grant](https://datatracker.ietf.org/doc/html/rfc8628)
1339+ - [RFC 8693 : OAuth 2.0 Token Exchange](https://datatracker.ietf.org/doc/html/rfc8693)
1340+ - [RFC 9068 : JSON Web Token (JWT) Profile for OAuth 2.0 Access Tokens](https://datatracker.ietf.org/doc/html/rfc9068)
1341+
1342+
11461343# IPP Data File API
11471344
11481345The IPP data file API provides functions to read and write IPP attributes and
0 commit comments