light-openid 2.0.3

Lightweight OpenID primitives & client
Documentation
//! # OpenID primitives
//!
//! These primitives might be incomplete, but sufficient for a basic OpenID usage.

/// OpenID discovery information, typically distributed on http://provider/.well-known/openid-configuration
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct OpenIDConfig {
    /// 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
    pub issuer: String,

    /// REQUIRED. URL of the OP's OAuth 2.0 Authorization Endpoint `OpenID.Core`
    pub authorization_endpoint: String,

    /// URL of the OP's OAuth 2.0 Token Endpoint `OpenID.Core`. This is REQUIRED unless only the Implicit Flow is used.
    pub token_endpoint: String,

    /// 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
    #[serde(skip_serializing_if = "Option::is_none")]
    pub userinfo_endpoint: Option<String>,

    /// 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.
    pub jwks_uri: String,

    /// 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.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub scopes_supported: Option<Vec<String>>,

    /// 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.
    pub response_types_supported: Vec<String>,

    /// REQUIRED. JSON array containing a list of the Subject Identifier types that this OP supports. Valid types include pairwise and public.
    pub subject_types_supported: Vec<String>,

    /// 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).
    pub id_token_signing_alg_values_supported: Vec<String>,

    /// 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
    #[serde(skip_serializing_if = "Option::is_none")]
    pub token_endpoint_auth_methods_supported: Option<Vec<String>>,

    /// 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.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub claims_supported: Option<Vec<String>>,

    /// OPTIONAL JSON array containing a list of Proof Key for Code Exchange (PKCE)
    #[serde(skip_serializing_if = "Option::is_none")]
    pub code_challenge_methods_supported: Option<Vec<String>>,

    /// 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.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub check_session_iframe: Option<String>,

    /// URL at the OP to which an RP can perform a redirect to request that the End-User be logged out at the OP.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub end_session_endpoint: Option<String>,
}

/// OpenID token response
///
/// The content of this field is specified in
/// * OAuth specifications: https://datatracker.ietf.org/doc/html/rfc6749#section-5.1
/// * OpenID Core specifications: https://openid.net/specs/openid-connect-core-1_0.html#TokenResponse
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct OpenIDTokenResponse {
    /// REQUIRED.  The access token issued by the authorization server.
    pub access_token: String,

    /// REQUIRED.  The type of the token issued. It MUST be "Bearer"
    pub token_type: String,

    /// OPTIONAL.  The refresh token, which can be used to obtain new
    ///          access tokens using the same authorization grant
    #[serde(skip_serializing_if = "Option::is_none")]
    pub refresh_token: Option<String>,

    ///  RECOMMENDED.  The lifetime in seconds of the access token.  For
    ///  example, the value "3600" denotes that the access token will
    ///  expire in one hour from the time the response was generated.
    ///  If omitted, the authorization server SHOULD provide the
    ///  expiration time via other means or document the default value.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub expires_in: Option<u64>,

    /// REQUIRED. ID Token value associated with the authenticated session.
    ///
    /// Note: this field is marked as optionnal because it is excluded in case
    /// of request of refresh token.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub id_token: Option<String>,
}

/// Refer to <https://openid.net/specs/openid-connect-core-1_0.html#StandardClaims> for more information
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct OpenIDUserInfo {
    /// Subject - Identifier for the End-User at the Issuer
    ///
    /// This is the only mandatory field
    pub sub: String,

    /// 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.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub name: Option<String>,

    /// 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.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub given_name: Option<String>,

    /// 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.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub family_name: Option<String>,

    /// 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
    #[serde(skip_serializing_if = "Option::is_none")]
    pub preferred_username: Option<String>,

    /// URL of the End-User's profile page. The contents of this Web page SHOULD be about the End-User.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub profile: Option<String>,

    /// 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.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub picture: Option<String>,

    /// 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.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub website: Option<String>,

    /// 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.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub email: Option<String>,

    /// 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.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub email_verified: Option<bool>,

    /// 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.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub birthdate: Option<String>,

    /// String from IANA Time Zone Database [IANA.time‑zones] representing the End-User's time zone. For example, Europe/Paris or America/Los_Angeles.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub zoneinfo: Option<String>,

    /// 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.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub locale: Option<String>,

    /// 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.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub phone_number: Option<String>,

    /// 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.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub phone_number_verified: Option<bool>,

    ///  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.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub address: Option<UserAddressClaim>,

    /// 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.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub updated_at: Option<i64>,
}

/// 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.
///
/// 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.
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct UserAddressClaim {
    /// 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").
    #[serde(skip_serializing_if = "Option::is_none")]
    pub formatted: Option<String>,

    /// 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").
    #[serde(skip_serializing_if = "Option::is_none")]
    pub street_address: Option<String>,

    /// City or locality component.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub locality: Option<String>,

    /// State, province, prefecture, or region component.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub region: Option<String>,

    /// Zip code or postal code component.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub postal_code: Option<String>,

    /// Country name component.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub country: Option<String>,
}

/// RP-Initiated Logout parameters
///
/// https://openid.net/specs/openid-connect-rpinitiated-1_0.html
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct RPInitiatedLogoutParameters {
    /// 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.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub id_token_hint: Option<String>,
    /// 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.)
    #[serde(skip_serializing_if = "Option::is_none")]
    pub logout_hint: Option<String>,
    /// 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.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub client_id: Option<String>,
    /// 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.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub post_logout_redirect_uri: Option<String>,
    /// 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.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub state: Option<String>,
    /// 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.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub ui_locales: Option<String>,
}