1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
//! Configuration
use serde::{Deserialize, Serialize};
/// Configuration for OpenID Connect
pub mod openid {
use super::*;
/// OpenID Metadata Urls
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Default)]
pub struct MetadataUrls {
/// The OpenID connect auth URL.
pub auth: String,
/// The OpenID token auth URL.
pub token: String,
/// The OpenID user info auth URL.
pub user_info: String,
/// The OpenID jwks url.
pub jwks: String,
}
/// OpenID Metadata Source
/// Defines how to fetch the openid metadata (auth_url, token_url, user_info_url, jwks_url)
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Default)]
pub enum MetadataSource {
#[default]
/// Using the discovery information living at `issuer_url/.well_known/openid-configuration` https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfig
Discovery,
/// Manual configuration
Manual(MetadataUrls),
}
/// OpenID Connect client configuration
///
/// ## Non-exhaustive
///
/// This struct is `#[non_exhaustive]`, so it is not possible to directly create a struct, creating a new struct
/// is done using the [`Config::new`] function. Additional properties are set using the `with_*` functions.
#[non_exhaustive]
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct Config {
/// The client ID
pub client_id: String,
/// The OpenID connect issuer URL.
pub issuer_url: String,
/// How to fetch the metadata
pub metadata_source: MetadataSource,
/// An override for the end session URL.
pub end_session_url: Option<String>,
/// The URL to navigate to after the logout has been completed.
pub after_logout_url: Option<String>,
/// The name of the query parameter for the post logout redirect.
/// The defaults to `post_logout_redirect_uri` for OpenID RP initiated logout.
/// However, e.g. older Keycloak instances, require this to be `redirect_uri`.
pub post_logout_redirect_name: Option<String>,
/// Additional audiences of the ID token which are considered trustworthy.
///
/// Those audiences are allowed in addition to the client ID.
pub additional_trusted_audiences: Vec<String>,
/// Specifies whether the issuer claim must match the expected issuer URL for the provider.
pub require_issuer_match: bool,
}
impl Config {
/// Create a new configuration
pub fn new(client_id: impl Into<String>, issuer_url: impl Into<String>) -> Self {
Self {
client_id: client_id.into(),
issuer_url: issuer_url.into(),
metadata_source: MetadataSource::Discovery,
end_session_url: None,
after_logout_url: None,
post_logout_redirect_name: None,
additional_trusted_audiences: vec![],
require_issuer_match: true,
}
}
/// Set an override for the URL for ending the session.
pub fn with_end_session_url(mut self, end_session_url: impl Into<String>) -> Self {
self.end_session_url = Some(end_session_url.into());
self
}
/// Set the URL the issuer should redirect to after the logout
pub fn with_after_logout_url(mut self, after_logout_url: impl Into<String>) -> Self {
self.after_logout_url = Some(after_logout_url.into());
self
}
/// Set the name of the post logout redirect query parameter
pub fn with_post_logout_redirect_name(
mut self,
post_logout_redirect_name: impl Into<String>,
) -> Self {
self.post_logout_redirect_name = Some(post_logout_redirect_name.into());
self
}
/// Set the additionally trusted audiences
pub fn with_additional_trusted_audiences(
mut self,
additional_trusted_audiences: impl IntoIterator<Item = impl Into<String>>,
) -> Self {
self.additional_trusted_audiences = additional_trusted_audiences
.into_iter()
.map(|s| s.into())
.collect();
self
}
/// Extend the additionally trusted audiences.
pub fn extend_additional_trusted_audiences(
mut self,
additional_trusted_audiences: impl IntoIterator<Item = impl Into<String>>,
) -> Self {
self.additional_trusted_audiences
.extend(additional_trusted_audiences.into_iter().map(|s| s.into()));
self
}
/// Add an additionally trusted audience.
pub fn add_additional_trusted_audience(
mut self,
additional_trusted_audience: impl Into<String>,
) -> Self {
self.additional_trusted_audiences
.push(additional_trusted_audience.into());
self
}
/// Specifies whether the issuer claim must match the expected issuer URL for the provider.
pub fn with_require_issuer_match(mut self, require_issuer_match: bool) -> Self {
self.require_issuer_match = require_issuer_match;
self
}
/// Set the metadata source
pub fn with_metadata_source(mut self, metadata_source: MetadataSource) -> Self {
self.metadata_source = metadata_source;
self
}
}
}
/// Configuration for OAuth2
pub mod oauth2 {
use super::*;
/// Plain OAuth2 client configuration
///
/// ## Non-exhaustive
///
/// This struct is `#[non_exhaustive]`, so it is not possible to directly create a struct, creating a new struct
/// is done using the [`crate::openid::Config::new`] function.
#[non_exhaustive]
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct Config {
/// The client ID
pub client_id: String,
/// The authentication URL
pub auth_url: String,
/// The token exchange URL
pub token_url: String,
}
impl Config {
/// Create a new configuration
pub fn new(
client_id: impl Into<String>,
auth_url: impl Into<String>,
token_url: impl Into<String>,
) -> Self {
Self {
client_id: client_id.into(),
auth_url: auth_url.into(),
token_url: token_url.into(),
}
}
}
}