Skip to main content

light_openid/
primitives.rs

1//! # OpenID primitives
2//!
3//! These primitives might be incomplete, but sufficient for a basic OpenID usage.
4
5use std::borrow::Cow;
6
7/// OpenID discovery information, typically distributed on http://provider/.well-known/openid-configuration
8#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
9pub struct OpenIDConfig {
10    /// URL using the https scheme with no query or fragment component that the OP asserts as its Issuer Identifier. If Issuer discovery is supported (see Section 2), this value MUST be identical to the issuer value returned by WebFinger. This also MUST be identical to the iss Claim value in ID Tokens issued from this Issuer
11    pub issuer: String,
12
13    /// REQUIRED. URL of the OP's OAuth 2.0 Authorization Endpoint `OpenID.Core`
14    pub authorization_endpoint: String,
15
16    /// URL of the OP's OAuth 2.0 Token Endpoint `OpenID.Core`. This is REQUIRED unless only the Implicit Flow is used.
17    pub token_endpoint: String,
18
19    /// RECOMMENDED. URL of the OP's UserInfo Endpoint `[`OpenID.Core`]`. This URL MUST use the https scheme and MAY contain port, path, and query parameter components
20    #[serde(skip_serializing_if = "Option::is_none")]
21    pub userinfo_endpoint: Option<String>,
22
23    /// REQUIRED. URL of the OP's JSON Web Key Set `[`JWK`]` document. This contains the signing key(s) the RP uses to validate signatures from the OP. The JWK Set MAY also contain the Server's encryption key(s), which are used by RPs to encrypt requests to the Server. When both signing and encryption keys are made available, a use (Key Use) parameter value is REQUIRED for all keys in the referenced JWK Set to indicate each key's intended usage. Although some algorithms allow the same key to be used for both signatures and encryption, doing so is NOT RECOMMENDED, as it is less secure. The JWK x5c parameter MAY be used to provide X.509 representations of keys provided. When used, the bare key values MUST still be present and MUST match those in the certificate.
24    pub jwks_uri: String,
25
26    /// RECOMMENDED. JSON array containing a list of the OAuth 2.0 `[`RFC6749`]` scope values that this server supports. The server MUST support the openid scope value. Servers MAY choose not to advertise some supported scope values even when this parameter is used, although those defined in `[`OpenID.Core`]` SHOULD be listed, if supported.
27    #[serde(skip_serializing_if = "Option::is_none")]
28    pub scopes_supported: Option<Vec<String>>,
29
30    /// REQUIRED. JSON array containing a list of the OAuth 2.0 response_type values that this OP supports. Dynamic OpenID Providers MUST support the code, id_token, and the token id_token Response Type values.
31    pub response_types_supported: Vec<String>,
32
33    /// REQUIRED. JSON array containing a list of the Subject Identifier types that this OP supports. Valid types include pairwise and public.
34    pub subject_types_supported: Vec<String>,
35
36    /// REQUIRED. JSON array containing a list of the JWS signing algorithms (alg values) supported by the OP for the ID Token to encode the Claims in a JWT `[`JWT`. The algorithm RS256 MUST be included. The value none MAY be supported, but MUST NOT be used unless the Response Type used returns no ID Token from the Authorization Endpoint (such as when using the Authorization Code Flow).
37    pub id_token_signing_alg_values_supported: Vec<String>,
38
39    /// OPTIONAL. JSON array containing a list of Client Authentication methods supported by this Token Endpoint. The options are client_secret_post, client_secret_basic, client_secret_jwt, and private_key_jwt
40    #[serde(skip_serializing_if = "Option::is_none")]
41    pub token_endpoint_auth_methods_supported: Option<Vec<String>>,
42
43    /// RECOMMENDED. JSON array containing a list of the Claim Names of the Claims that the OpenID Provider MAY be able to supply values for. Note that for privacy or other reasons, this might not be an exhaustive list.
44    #[serde(skip_serializing_if = "Option::is_none")]
45    pub claims_supported: Option<Vec<String>>,
46
47    /// OPTIONAL JSON array containing a list of Proof Key for Code Exchange (PKCE)
48    #[serde(skip_serializing_if = "Option::is_none")]
49    pub code_challenge_methods_supported: Option<Vec<String>>,
50
51    /// URL of an OP iframe that supports cross-origin communications for session state information with the RP Client, using the HTML5 postMessage API. The page is loaded from an invisible iframe embedded in an RP page so that it can run in the OP's security context. It accepts postMessage requests from the relevant RP iframe and uses postMessage to post back the login status of the End-User at the OP.
52    #[serde(skip_serializing_if = "Option::is_none")]
53    pub check_session_iframe: Option<String>,
54
55    /// URL at the OP to which an RP can perform a redirect to request that the End-User be logged out at the OP.
56    #[serde(skip_serializing_if = "Option::is_none")]
57    pub end_session_endpoint: Option<String>,
58}
59
60/// OpenID token response
61///
62/// The content of this field is specified in
63/// * OAuth specifications: https://datatracker.ietf.org/doc/html/rfc6749#section-5.1
64/// * OpenID Core specifications: https://openid.net/specs/openid-connect-core-1_0.html#TokenResponse
65#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
66pub struct OpenIDTokenResponse {
67    /// REQUIRED.  The access token issued by the authorization server.
68    pub access_token: String,
69
70    /// REQUIRED.  The type of the token issued. It MUST be "Bearer"
71    pub token_type: String,
72
73    /// OPTIONAL.  The refresh token, which can be used to obtain new
74    ///          access tokens using the same authorization grant
75    #[serde(skip_serializing_if = "Option::is_none")]
76    pub refresh_token: Option<String>,
77
78    ///  RECOMMENDED.  The lifetime in seconds of the access token.  For
79    ///  example, the value "3600" denotes that the access token will
80    ///  expire in one hour from the time the response was generated.
81    ///  If omitted, the authorization server SHOULD provide the
82    ///  expiration time via other means or document the default value.
83    #[serde(skip_serializing_if = "Option::is_none")]
84    pub expires_in: Option<u64>,
85
86    /// REQUIRED. ID Token value associated with the authenticated session.
87    ///
88    /// Note: this field is marked as optionnal because it is excluded in case
89    /// of request of refresh token.
90    #[serde(skip_serializing_if = "Option::is_none")]
91    pub id_token: Option<String>,
92}
93
94/// OpenID IdToken information
95#[derive(serde::Serialize, serde::Deserialize, Debug)]
96pub struct OpenIDToken {
97    /// REQUIRED. Issuer Identifier for the Issuer of the response. The iss value is a case sensitive URL using the https scheme that contains scheme, host, and optionally, port number and path components and no query or fragment components.
98    pub iss: String,
99    /// REQUIRED. Subject Identifier. A locally unique and never reassigned identifier within the Issuer for the End-User, which is intended to be consumed by the Client, e.g., 24400320 or AItOawmwtWwcT0k51BayewNvutrJUqsvl6qs7A4. It MUST NOT exceed 255 ASCII characters in length. The sub value is a case sensitive string.
100    pub sub: String,
101    /// REQUIRED. Audience(s) that this ID Token is intended for. It MUST contain the OAuth 2.0 client_id of the Relying Party as an audience value. It MAY also contain identifiers for other audiences. In the general case, the aud value is an array of case sensitive strings. In the common special case when there is one audience, the aud value MAY be a single case sensitive string.
102    pub aud: String,
103    /// REQUIRED. Expiration time on or after which the ID Token MUST NOT be accepted for processing. The processing of this parameter requires that the current date/time MUST be before the expiration date/time listed in the value. Implementers MAY provide for some small leeway, usually no more than a few minutes, to account for clock skew. Its value is a JSON number representing the number of seconds from 1970-01-01T0:0:0Z as measured in UTC until the date/time. See RFC 3339 for details regarding date/times in general and UTC in particular.
104    pub exp: u64,
105    /// REQUIRED. Time at which the JWT was issued. Its value is a JSON number representing the number of seconds from 1970-01-01T0:0:0Z as measured in UTC until the date/time.
106    pub iat: u64,
107    /// Time when the End-User authentication occurred. Its value is a JSON number representing the number of seconds from 1970-01-01T0:0:0Z as measured in UTC until the date/time. When a max_age request is made or when auth_time is requested as an Essential Claim, then this Claim is REQUIRED; otherwise, its inclusion is OPTIONAL. (The auth_time Claim semantically corresponds to the OpenID 2.0 PAPE [OpenID.PAPE] auth_time response parameter.)
108    #[serde(skip_serializing_if = "Option::is_none")]
109    pub auth_time: Option<u64>,
110    /// String value used to associate a Client session with an ID Token, and to mitigate replay attacks. The value is passed through unmodified from the Authentication Request to the ID Token. If present in the ID Token, Clients MUST verify that the nonce Claim Value is equal to the value of the nonce parameter sent in the Authentication Request. If present in the Authentication Request, Authorization Servers MUST include a nonce Claim in the ID Token with the Claim Value being the nonce value sent in the Authentication Request. Authorization Servers SHOULD perform no other processing on nonce values used. The nonce value is a case sensitive string.
111    #[serde(skip_serializing_if = "Option::is_none")]
112    pub nonce: Option<String>,
113    /// OPTIONAL. Authentication Context Class Reference. String specifying an Authentication Context Class Reference value that identifies the Authentication Context Class that the authentication performed satisfied. The value "0" indicates the End-User authentication did not meet the requirements of ISO/IEC 29115 [ISO29115] level 1. For historic reasons, the value "0" is used to indicate that there is no confidence that the same person is actually there. Authentications with level 0 SHOULD NOT be used to authorize access to any resource of any monetary value. (This corresponds to the OpenID 2.0 PAPE [OpenID.PAPE] nist_auth_level 0.) An absolute URI or an RFC 6711 [RFC6711] registered name SHOULD be used as the acr value; registered names MUST NOT be used with a different meaning than that which is registered. Parties using this claim will need to agree upon the meanings of the values used, which may be context specific. The acr value is a case-sensitive string.
114    #[serde(skip_serializing_if = "Option::is_none")]
115    pub acr: Option<String>,
116    /// OPTIONAL. Authentication Methods References. JSON array of strings that are identifiers for authentication methods used in the authentication. For instance, values might indicate that both password and OTP authentication methods were used. The amr value is an array of case-sensitive strings. Values used in the amr Claim SHOULD be from those registered in the IANA Authentication Method Reference Values registry [IANA.AMR] established by [RFC8176]; parties using this claim will need to agree upon the meanings of any unregistered values used, which may be context specific.
117    #[serde(skip_serializing_if = "Option::is_none")]
118    pub amr: Option<String>,
119    /// OPTIONAL. Authorized party - the party to which the ID Token was issued. If present, it MUST contain the OAuth 2.0 Client ID of this party. The azp value is a case-sensitive string containing a StringOrURI value. Note that in practice, the azp Claim only occurs when extensions beyond the scope of this specification are used; therefore, implementations not using such extensions are encouraged to not use azp and to ignore it when it does occur.
120    #[serde(skip_serializing_if = "Option::is_none")]
121    pub azp: Option<String>,
122}
123
124/// Refer to <https://openid.net/specs/openid-connect-core-1_0.html#StandardClaims> for more information
125#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
126pub struct OpenIDUserInfo {
127    /// Subject - Identifier for the End-User at the Issuer
128    ///
129    /// This is the only mandatory field
130    pub sub: String,
131
132    /// End-User's full name in displayable form including all name parts, possibly including titles and suffixes, ordered according to the End-User's locale and preferences.
133    #[serde(skip_serializing_if = "Option::is_none")]
134    pub name: Option<String>,
135
136    /// Given name(s) or first name(s) of the End-User. Note that in some cultures, people can have multiple given names; all can be present, with the names being separated by space characters.
137    #[serde(skip_serializing_if = "Option::is_none")]
138    pub given_name: Option<String>,
139
140    /// Surname(s) or last name(s) of the End-User. Note that in some cultures, people can have multiple family names or no family name; all can be present, with the names being separated by space characters.
141    #[serde(skip_serializing_if = "Option::is_none")]
142    pub family_name: Option<String>,
143
144    /// Shorthand name by which the End-User wishes to be referred to at the RP, such as janedoe or j.doe. This value MAY be any valid JSON string including special characters such as @, /, or whitespace. The RP MUST NOT rely upon this value being unique, as discussed in
145    #[serde(skip_serializing_if = "Option::is_none")]
146    pub preferred_username: Option<String>,
147
148    /// URL of the End-User's profile page. The contents of this Web page SHOULD be about the End-User.
149    #[serde(skip_serializing_if = "Option::is_none")]
150    pub profile: Option<String>,
151
152    /// URL of the End-User's profile picture. This URL MUST refer to an image file (for example, a PNG, JPEG, or GIF image file), rather than to a Web page containing an image. Note that this URL SHOULD specifically reference a profile photo of the End-User suitable for displaying when describing the End-User, rather than an arbitrary photo taken by the End-User.
153    #[serde(skip_serializing_if = "Option::is_none")]
154    pub picture: Option<String>,
155
156    /// URL of the End-User's Web page or blog. This Web page SHOULD contain information published by the End-User or an organization that the End-User is affiliated with.
157    #[serde(skip_serializing_if = "Option::is_none")]
158    pub website: Option<String>,
159
160    /// End-User's preferred e-mail address. Its value MUST conform to the RFC 5322 RFC5322 addr-spec syntax. The RP MUST NOT rely upon this value being unique, as discussed in Section 5.7.
161    #[serde(skip_serializing_if = "Option::is_none")]
162    pub email: Option<String>,
163
164    /// True if the End-User's e-mail address has been verified; otherwise false. When this Claim Value is true, this means that the OP took affirmative steps to ensure that this e-mail address was controlled by the End-User at the time the verification was performed. The means by which an e-mail address is verified is context-specific, and dependent upon the trust framework or contractual agreements within which the parties are operating.
165    #[serde(skip_serializing_if = "Option::is_none")]
166    pub email_verified: Option<bool>,
167
168    /// End-User's birthday, represented as an ISO 8601-1 [ISO8601‑1] YYYY-MM-DD format. The year MAY be 0000, indicating that it is omitted. To represent only the year, YYYY format is allowed. Note that depending on the underlying platform's date related function, providing just year can result in varying month and day, so the implementers need to take this factor into account to correctly process the dates.
169    #[serde(skip_serializing_if = "Option::is_none")]
170    pub birthdate: Option<String>,
171
172    /// String from IANA Time Zone Database [IANA.time‑zones] representing the End-User's time zone. For example, Europe/Paris or America/Los_Angeles.
173    #[serde(skip_serializing_if = "Option::is_none")]
174    pub zoneinfo: Option<String>,
175
176    /// End-User's locale, represented as a BCP47 [RFC5646] language tag. This is typically an ISO 639 Alpha-2 [ISO639] language code in lowercase and an ISO 3166-1 Alpha-2 [ISO3166‑1] country code in uppercase, separated by a dash. For example, en-US or fr-CA. As a compatibility note, some implementations have used an underscore as the separator rather than a dash, for example, en_US; Relying Parties MAY choose to accept this locale syntax as well.
177    #[serde(skip_serializing_if = "Option::is_none")]
178    pub locale: Option<String>,
179
180    /// End-User's preferred telephone number. E.164 [E.164] is RECOMMENDED as the format of this Claim, for example, +1 (425) 555-1212 or +56 (2) 687 2400. If the phone number contains an extension, it is RECOMMENDED that the extension be represented using the RFC 3966 [RFC3966] extension syntax, for example, +1 (604) 555-1234;ext=5678.
181    #[serde(skip_serializing_if = "Option::is_none")]
182    pub phone_number: Option<String>,
183
184    /// True if the End-User's phone number has been verified; otherwise false. When this Claim Value is true, this means that the OP took affirmative steps to ensure that this phone number was controlled by the End-User at the time the verification was performed. The means by which a phone number is verified is context specific, and dependent upon the trust framework or contractual agreements within which the parties are operating. When true, the phone_number Claim MUST be in E.164 format and any extensions MUST be represented in RFC 3966 format.
185    #[serde(skip_serializing_if = "Option::is_none")]
186    pub phone_number_verified: Option<bool>,
187
188    ///  End-User's preferred postal address. The value of the address member is a JSON [RFC8259] structure containing some or all of the members defined in Section 5.1.1.
189    #[serde(skip_serializing_if = "Option::is_none")]
190    pub address: Option<UserAddressClaim>,
191
192    /// Time the End-User's information was last updated. Its value is a JSON number representing the number of seconds from 1970-01-01T00:00:00Z as measured in UTC until the date/time.
193    #[serde(skip_serializing_if = "Option::is_none")]
194    pub updated_at: Option<i64>,
195}
196
197/// The Address Claim represents a physical mailing address. Implementations MAY return only a subset of the fields of an address, depending upon the information available and the End-User's privacy preferences. For example, the country and region might be returned without returning more fine-grained address information.
198///
199/// Implementations MAY return just the full address as a single string in the formatted sub-field, or they MAY return just the individual component fields using the other sub-fields, or they MAY return both. If both variants are returned, they SHOULD represent the same address, with the formatted address indicating how the component fields are combined.
200#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
201pub struct UserAddressClaim {
202    /// Full mailing address, formatted for display or use on a mailing label. This field MAY contain multiple lines, separated by newlines. Newlines can be represented either as a carriage return/line feed pair ("\r\n") or as a single line feed character ("\n").
203    #[serde(skip_serializing_if = "Option::is_none")]
204    pub formatted: Option<String>,
205
206    /// Full street address component, which MAY include house number, street name, Post Office Box, and multi-line extended street address information. This field MAY contain multiple lines, separated by newlines. Newlines can be represented either as a carriage return/line feed pair ("\r\n") or as a single line feed character ("\n").
207    #[serde(skip_serializing_if = "Option::is_none")]
208    pub street_address: Option<String>,
209
210    /// City or locality component.
211    #[serde(skip_serializing_if = "Option::is_none")]
212    pub locality: Option<String>,
213
214    /// State, province, prefecture, or region component.
215    #[serde(skip_serializing_if = "Option::is_none")]
216    pub region: Option<String>,
217
218    /// Zip code or postal code component.
219    #[serde(skip_serializing_if = "Option::is_none")]
220    pub postal_code: Option<String>,
221
222    /// Country name component.
223    #[serde(skip_serializing_if = "Option::is_none")]
224    pub country: Option<String>,
225}
226
227/// OpenID Authorize query parameters
228#[derive(serde::Serialize, serde::Deserialize, Clone, Debug)]
229pub struct AuthorizeQuery<'a> {
230    /// REQUIRED. OpenID Connect requests MUST contain the openid scope value. If the openid scope value is not present, the behavior is entirely unspecified. Other scope values MAY be present. Scope values used that are not understood by an implementation SHOULD be ignored. See Sections 5.4 and 11 for additional scope values defined by this specification.
231    pub scope: Cow<'a, str>,
232
233    /// REQUIRED. OAuth 2.0 Response Type value that determines the authorization processing flow to be used, including what parameters are returned from the endpoints used. When using the Authorization Code Flow, this value is code.
234    pub response_type: Cow<'a, str>,
235
236    /// REQUIRED. OAuth 2.0 Client Identifier valid at the Authorization Server.
237    pub client_id: Cow<'a, str>,
238
239    /// REQUIRED. Redirection URI to which the response will be sent. This URI MUST exactly match one of the Redirection URI values for the Client pre-registered at the OpenID Provider, with the matching performed as described in Section 6.2.1 of RFC3986 (Simple String Comparison). When using this flow, the Redirection URI SHOULD use the https scheme; however, it MAY use the http scheme, provided that the Client Type is confidential, as defined in Section 2.1 of OAuth 2.0, and provided the OP allows the use of http Redirection URIs in this case. The Redirection URI MAY use an alternate scheme, such as one that is intended to identify a callback into a native application.
240    pub redirect_uri: Cow<'a, str>,
241
242    /// RECOMMENDED. Opaque value used to maintain state between the request and the callback. Typically, Cross-Site Request Forgery (CSRF, XSRF) mitigation is done by cryptographically binding the value of this parameter with a browser cookie.
243    #[serde(skip_serializing_if = "Option::is_none")]
244    pub state: Option<Cow<'a, str>>,
245
246    /// OPTIONAL. Informs the Authorization Server of the mechanism to be used for returning parameters from the Authorization Endpoint. This use of this parameter is NOT RECOMMENDED when the Response Mode that would be requested is the default mode specified for the Response Type.
247    #[serde(skip_serializing_if = "Option::is_none")]
248    pub response_mode: Option<Cow<'a, str>>,
249
250    /// OPTIONAL. String value used to associate a Client session with an ID Token, and to mitigate replay attacks. The value is passed through unmodified from the Authentication Request to the ID Token. Sufficient entropy MUST be present in the nonce values used to prevent attackers from guessing values.
251    #[serde(skip_serializing_if = "Option::is_none")]
252    pub nonce: Option<Cow<'a, str>>,
253
254    /// OPTIONAL. - Code Challenge. <https://ldapwiki.com/wiki/Code_challenge_method>
255    #[serde(skip_serializing_if = "Option::is_none")]
256    pub code_challenge: Option<Cow<'a, str>>,
257
258    /// OPTIONAL, defaults to "plain" if not present in the request.  Code
259    ///       verifier transformation method is "S256" or "plain".
260    #[serde(skip_serializing_if = "Option::is_none")]
261    pub code_challenge_method: Option<Cow<'a, str>>,
262}
263
264/// RP-Initiated Logout query parameters
265///
266/// https://openid.net/specs/openid-connect-rpinitiated-1_0.html
267#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
268pub struct RPInitiatedLogoutParameters {
269    /// RECOMMENDED. ID Token previously issued by the OP to the RP passed to the Logout Endpoint as a hint about the End-User's current authenticated session with the Client. This is used as an indication of the identity of the End-User that the RP is requesting be logged out by the OP.
270    #[serde(skip_serializing_if = "Option::is_none")]
271    pub id_token_hint: Option<String>,
272    /// OPTIONAL. Hint to the Authorization Server about the End-User that is logging out. The value and meaning of this parameter is left up to the OP's discretion. For instance, the value might contain an email address, phone number, username, or session identifier pertaining to the RP's session with the OP for the End-User. (This parameter is intended to be analogous to the login_hint parameter defined in Section 3.1.2.1 of OpenID Connect Core 1.0 [OpenID.Core] that is used in Authentication Requests; whereas, logout_hint is used in RP-Initiated Logout Requests.)
273    #[serde(skip_serializing_if = "Option::is_none")]
274    pub logout_hint: Option<String>,
275    /// OPTIONAL. OAuth 2.0 Client Identifier valid at the Authorization Server. When both client_id and id_token_hint are present, the OP MUST verify that the Client Identifier matches the one used when issuing the ID Token. The most common use case for this parameter is to specify the Client Identifier when post_logout_redirect_uri is used but id_token_hint is not. Another use is for symmetrically encrypted ID Tokens used as id_token_hint values that require the Client Identifier to be specified by other means, so that the ID Tokens can be decrypted by the OP.
276    #[serde(skip_serializing_if = "Option::is_none")]
277    pub client_id: Option<String>,
278    /// OPTIONAL. URI to which the RP is requesting that the End-User's User Agent be redirected after a logout has been performed. This URI SHOULD use the https scheme and MAY contain port, path, and query parameter components; however, it MAY use the http scheme, provided that the Client Type is confidential, as defined in Section 2.1 of OAuth 2.0 [RFC6749], and provided the OP allows the use of http RP URIs. The URI MAY use an alternate scheme, such as one that is intended to identify a callback into a native application. The value MUST have been previously registered with the OP, either using the post_logout_redirect_uris Registration parameter or via another mechanism. An id_token_hint is also RECOMMENDED when this parameter is included.
279    #[serde(skip_serializing_if = "Option::is_none")]
280    pub post_logout_redirect_uri: Option<String>,
281    /// OPTIONAL. Opaque value used by the RP to maintain state between the logout request and the callback to the endpoint specified by the post_logout_redirect_uri parameter. If included in the logout request, the OP passes this value back to the RP using the state parameter when redirecting the User Agent back to the RP.
282    #[serde(skip_serializing_if = "Option::is_none")]
283    pub state: Option<String>,
284    /// OPTIONAL. End-User's preferred languages and scripts for the user interface, represented as a space-separated list of BCP47 [RFC5646] language tag values, ordered by preference. For instance, the value "fr-CA fr en" represents a preference for French as spoken in Canada, then French (without a region designation), followed by English (without a region designation). An error SHOULD NOT result if some or all of the requested locales are not supported by the OpenID Provider.
285    #[serde(skip_serializing_if = "Option::is_none")]
286    pub ui_locales: Option<String>,
287}