Skip to content

Commit be05ff8

Browse files
feat: add redirect origin (#215)
1 parent 765f2da commit be05ff8

File tree

33 files changed

+513
-109
lines changed

33 files changed

+513
-109
lines changed

Cargo.lock

Lines changed: 15 additions & 12 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ tower-service = "0.3.3"
8282
tower-sessions = "0.14.0"
8383
tracing = "0.1.41"
8484
tracing-subscriber = "0.3.19"
85+
url = "2.5.7"
8586
utoipa = { version = "5.3.1", features = ["chrono", "uuid"] }
8687
utoipa-axum = "0.2.0"
8788
uuid = "1.11.0"

examples/axum/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,5 +20,6 @@ tokio = { workspace = true, features = ["macros", "rt-multi-thread"] }
2020
tower-sessions.workspace = true
2121
tracing.workspace = true
2222
tracing-subscriber.workspace = true
23+
url.workspace = true
2324
utoipa-axum.workspace = true
2425
utoipa-scalar = { version = "0.3.0", features = ["axum"] }

examples/axum/src/main.rs

Lines changed: 22 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,12 @@ use axum::{Json, middleware::from_fn, routing::get};
55
use shield::{Shield, ShieldOptions};
66
use shield_axum::{AuthRoutes, ShieldLayer, auth_required};
77
use shield_memory::{MemoryStorage, User};
8-
use shield_oidc::{Keycloak, OidcMethod};
8+
use shield_oidc::{Keycloak, OidcMethod, OidcOptions};
99
use time::Duration;
1010
use tokio::net::TcpListener;
1111
use tower_sessions::{Expiry, MemoryStore, SessionManagerLayer};
1212
use tracing::{info, level_filters::LevelFilter};
13+
use url::Url;
1314
use utoipa_axum::router::OpenApiRouter;
1415
use utoipa_scalar::{Scalar, Servable};
1516

@@ -34,17 +35,26 @@ async fn main() {
3435
let shield = Shield::new(
3536
storage.clone(),
3637
vec![Arc::new(
37-
OidcMethod::new(storage).with_providers([Keycloak::builder(
38-
"keycloak",
39-
"http://localhost:18080/realms/Shield",
40-
"client1",
41-
)
42-
.client_secret("xcpQsaGbRILTljPtX4npjmYMBjKrariJ")
43-
.redirect_url(format!(
44-
"http://localhost:{}/api/auth/oidc/sign-in-callback/keycloak",
45-
addr.port()
46-
))
47-
.build()]),
38+
OidcMethod::new(storage)
39+
.with_providers([Keycloak::builder(
40+
"keycloak",
41+
"http://localhost:18080/realms/Shield",
42+
"client1",
43+
)
44+
.client_secret("xcpQsaGbRILTljPtX4npjmYMBjKrariJ")
45+
.redirect_url(format!(
46+
"http://localhost:{}/api/auth/oidc/sign-in-callback/keycloak",
47+
addr.port()
48+
))
49+
.build()])
50+
.with_options(
51+
OidcOptions::builder()
52+
.redirect_origins([
53+
Url::parse(&format!("http://localhost:{}", addr.port())).unwrap(),
54+
Url::parse("http://localhost:5173").unwrap(),
55+
])
56+
.build(),
57+
),
4858
)],
4959
ShieldOptions::default(),
5060
);

packages/core/shield/src/actions/sign_in_callback.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::{MethodSession, Provider, ShieldError};
1+
use crate::{error::ShieldError, provider::Provider, session::MethodSession};
22

33
const ACTION_ID: &str = "sign-in-callback";
44
const ACTION_NAME: &str = "Sign in callback";

packages/core/shield/src/actions/sign_out.rs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
1-
use crate::{Form, Input, InputType, InputTypeSubmit, MethodSession, Provider, ShieldError};
1+
use crate::{
2+
error::ShieldError,
3+
form::{Form, Input, InputType, InputTypeSubmit, InputValue},
4+
provider::Provider,
5+
session::MethodSession,
6+
};
27

38
const ACTION_ID: &str = "sign-out";
49
const ACTION_NAME: &str = "Sign out";
@@ -37,7 +42,9 @@ impl SignOutAction {
3742
name: "submit".to_owned(),
3843
label: None,
3944
r#type: InputType::Submit(InputTypeSubmit {}),
40-
value: Some(Self::name()),
45+
value: Some(InputValue::String {
46+
value: Self::name(),
47+
}),
4148
}],
4249
}])
4350
}

packages/core/shield/src/form.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,15 @@ pub struct Input {
1414
pub name: String,
1515
pub label: Option<String>,
1616
pub r#type: InputType,
17-
pub value: Option<String>,
17+
pub value: Option<InputValue>,
18+
}
19+
20+
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
21+
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
22+
#[serde(tag = "type", rename_all = "kebab-case")]
23+
pub enum InputValue {
24+
Origin,
25+
String { value: String },
1826
}
1927

2028
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]

packages/integrations/shield-react/src/client/@tanstack/react-query.gen.ts

Lines changed: 87 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,25 @@
11
// This file is auto-generated by @hey-api/openapi-ts
2-
import { type UseMutationOptions, queryOptions } from '@tanstack/react-query';
2+
import { type DefaultError, type UseMutationOptions, queryOptions } from '@tanstack/react-query';
33

44
import { client } from '../client.gen.js';
5-
import { type Options, callAction, getActionForms, getCurrentUser } from '../sdk.gen.js';
6-
import type { CallActionData, CallActionError, GetActionFormsData, GetCurrentUserData } from '../types.gen.js';
5+
import {
6+
type Options,
7+
callAction,
8+
getActionForms,
9+
getCurrentUser,
10+
signInCallbackOidc,
11+
signInOidc,
12+
signOutOidc,
13+
} from '../sdk.gen.js';
14+
import type {
15+
CallActionData,
16+
CallActionError,
17+
GetActionFormsData,
18+
GetCurrentUserData,
19+
SignInCallbackOidcData,
20+
SignInOidcData,
21+
SignOutOidcData,
22+
} from '../types.gen.js';
723

824
export type QueryKey<TOptions extends Options> = [
925
Pick<TOptions, 'baseUrl' | 'body' | 'headers' | 'path' | 'query'> & {
@@ -49,6 +65,7 @@ export const getActionFormsQueryKey = (options: Options<GetActionFormsData>) =>
4965

5066
/**
5167
* Get action forms
68+
*
5269
* Get action forms.
5370
*/
5471
export const getActionFormsOptions = (options: Options<GetActionFormsData>) => {
@@ -66,11 +83,77 @@ export const getActionFormsOptions = (options: Options<GetActionFormsData>) => {
6683
});
6784
};
6885

86+
export const signInCallbackOidcQueryKey = (options: Options<SignInCallbackOidcData>) =>
87+
createQueryKey('signInCallbackOidc', options);
88+
89+
/**
90+
* Sign in callback for OpenID Connect
91+
*
92+
* Sign in callback for OpenID Connect.
93+
*/
94+
export const signInCallbackOidcOptions = (options: Options<SignInCallbackOidcData>) => {
95+
return queryOptions({
96+
queryFn: async ({ queryKey, signal }) => {
97+
const { data } = await signInCallbackOidc({
98+
...options,
99+
...queryKey[0],
100+
signal,
101+
throwOnError: true,
102+
});
103+
return data;
104+
},
105+
queryKey: signInCallbackOidcQueryKey(options),
106+
});
107+
};
108+
109+
/**
110+
* Sign in with OpenID Connect
111+
*
112+
* Sign in with OpenID Connect.
113+
*/
114+
export const signInOidcMutation = (
115+
options?: Partial<Options<SignInOidcData>>,
116+
): UseMutationOptions<unknown, DefaultError, Options<SignInOidcData>> => {
117+
const mutationOptions: UseMutationOptions<unknown, DefaultError, Options<SignInOidcData>> = {
118+
mutationFn: async (fnOptions) => {
119+
const { data } = await signInOidc({
120+
...options,
121+
...fnOptions,
122+
throwOnError: true,
123+
});
124+
return data;
125+
},
126+
};
127+
return mutationOptions;
128+
};
129+
130+
/**
131+
* Sign out with OpenID Connect
132+
*
133+
* Sign out with OpenID Connect.
134+
*/
135+
export const signOutOidcMutation = (
136+
options?: Partial<Options<SignOutOidcData>>,
137+
): UseMutationOptions<unknown, DefaultError, Options<SignOutOidcData>> => {
138+
const mutationOptions: UseMutationOptions<unknown, DefaultError, Options<SignOutOidcData>> = {
139+
mutationFn: async (fnOptions) => {
140+
const { data } = await signOutOidc({
141+
...options,
142+
...fnOptions,
143+
throwOnError: true,
144+
});
145+
return data;
146+
},
147+
};
148+
return mutationOptions;
149+
};
150+
69151
export const getCurrentUserQueryKey = (options?: Options<GetCurrentUserData>) =>
70152
createQueryKey('getCurrentUser', options);
71153

72154
/**
73155
* Get current user
156+
*
74157
* Get the current user account.
75158
*/
76159
export const getCurrentUserOptions = (options?: Options<GetCurrentUserData>) => {
@@ -90,6 +173,7 @@ export const getCurrentUserOptions = (options?: Options<GetCurrentUserData>) =>
90173

91174
/**
92175
* Call action
176+
*
93177
* Call an action.
94178
*/
95179
export const callActionMutation = (

packages/integrations/shield-react/src/client/client/index.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ export type {
1616
Config,
1717
CreateClientConfig,
1818
Options,
19-
OptionsLegacyParser,
2019
RequestOptions,
2120
RequestResult,
2221
ResolvedRequestOptions,

packages/integrations/shield-react/src/client/client/types.gen.ts

Lines changed: 2 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@ type BuildUrlFn = <
163163
url: string;
164164
},
165165
>(
166-
options: Pick<TData, 'url'> & Options<TData>,
166+
options: TData & Options<TData>,
167167
) => string;
168168

169169
export type Client = CoreClient<RequestFn, Config, MethodFn, BuildUrlFn, SseFn> & {
@@ -198,20 +198,4 @@ export type Options<
198198
TResponse = unknown,
199199
TResponseStyle extends ResponseStyle = 'fields',
200200
> = OmitKeys<RequestOptions<TResponse, TResponseStyle, ThrowOnError>, 'body' | 'path' | 'query' | 'url'> &
201-
Omit<TData, 'url'>;
202-
203-
export type OptionsLegacyParser<
204-
TData = unknown,
205-
ThrowOnError extends boolean = boolean,
206-
TResponseStyle extends ResponseStyle = 'fields',
207-
> = TData extends { body?: any }
208-
? TData extends { headers?: any }
209-
? OmitKeys<RequestOptions<unknown, TResponseStyle, ThrowOnError>, 'body' | 'headers' | 'url'> & TData
210-
: OmitKeys<RequestOptions<unknown, TResponseStyle, ThrowOnError>, 'body' | 'url'> &
211-
TData &
212-
Pick<RequestOptions<unknown, TResponseStyle, ThrowOnError>, 'headers'>
213-
: TData extends { headers?: any }
214-
? OmitKeys<RequestOptions<unknown, TResponseStyle, ThrowOnError>, 'headers' | 'url'> &
215-
TData &
216-
Pick<RequestOptions<unknown, TResponseStyle, ThrowOnError>, 'body'>
217-
: OmitKeys<RequestOptions<unknown, TResponseStyle, ThrowOnError>, 'url'> & TData;
201+
([TData] extends [never] ? unknown : Omit<TData, 'url'>);

0 commit comments

Comments
 (0)