Compare commits

...

2 Commits

Author SHA1 Message Date
codegen-sh[bot] a7475ac352 feat: Support OIDC id_token_hint in Logout URL 2025-03-28 21:41:55 +00:00
codegen-sh[bot] a51456deb3 Add missing JSDoc to shared components (#8829)
Co-authored-by: codegen-sh[bot] <131295404+codegen-sh[bot]@users.noreply.github.com>
2025-03-28 14:27:30 -07:00
10 changed files with 48 additions and 6 deletions
+5 -1
View File
@@ -235,7 +235,11 @@ export const logout = createAction({
await stores.auth.logout();
if (env.OIDC_LOGOUT_URI) {
setTimeout(() => {
window.location.replace(env.OIDC_LOGOUT_URI);
let logoutUri = env.OIDC_LOGOUT_URI;
if (stores.auth.idToken && logoutUri.includes("{id_token}")) {
logoutUri = logoutUri.replace("{id_token}", stores.auth.idToken);
}
window.location.replace(logoutUri);
}, 200);
}
},
+6 -1
View File
@@ -10,7 +10,12 @@ const Logout = () => {
void auth.logout().then(() => {
if (env.OIDC_LOGOUT_URI) {
setTimeout(() => {
window.location.replace(env.OIDC_LOGOUT_URI);
// If the logout URI contains a template for the id_token, replace it
let logoutUri = env.OIDC_LOGOUT_URI;
if (auth.idToken && logoutUri.includes("{id_token}")) {
logoutUri = logoutUri.replace("{id_token}", auth.idToken);
}
window.location.replace(logoutUri);
}, 200);
}
});
+10 -1
View File
@@ -18,7 +18,7 @@ import Store from "./base/Store";
type PersistedData = Pick<
AuthStore,
"user" | "team" | "collaborationToken" | "availableTeams" | "policies"
"user" | "team" | "collaborationToken" | "idToken" | "availableTeams" | "policies"
>;
type Provider = {
@@ -50,6 +50,10 @@ export default class AuthStore extends Store<Team> {
@observable
public collaborationToken?: string | null;
/* The ID token from OIDC authentication, used for logout */
@observable
public idToken?: string | null;
/* A list of teams that the current user has access to. */
@observable
public availableTeams?: {
@@ -133,6 +137,7 @@ export default class AuthStore extends Store<Team> {
this.currentTeamId = data.team?.id;
this.currentUserId = data.user?.id;
this.collaborationToken = data.collaborationToken;
this.idToken = data.idToken;
this.lastSignedIn = getCookie("lastSignedIn");
}
@@ -171,6 +176,7 @@ export default class AuthStore extends Store<Team> {
user: this.user,
team: this.team,
collaborationToken: this.collaborationToken,
idToken: this.idToken,
availableTeams: this.availableTeams,
policies: this.policies,
};
@@ -205,6 +211,7 @@ export default class AuthStore extends Store<Team> {
this.availableTeams = res.data.availableTeams;
this.collaborationToken = res.data.collaborationToken;
this.idToken = res.data.id_token;
if (env.SENTRY_DSN) {
Sentry.configureScope((scope) => {
@@ -261,6 +268,7 @@ export default class AuthStore extends Store<Team> {
this.currentUserId = null;
this.currentTeamId = null;
this.collaborationToken = null;
this.idToken = null;
this.availableTeams = this.availableTeams?.filter(
(team) => team.id !== this.team?.id
);
@@ -333,6 +341,7 @@ export default class AuthStore extends Store<Team> {
this.currentUserId = null;
this.currentTeamId = null;
this.collaborationToken = null;
this.idToken = null;
this.rootStore.clear();
// Tell the host application we logged out, if any allows window cleanup.
+2 -2
View File
@@ -58,7 +58,7 @@ if (
ctx: Context,
accessToken: string,
refreshToken: string,
params: { expires_in: number },
params: { expires_in: number; id_token?: string },
_profile: unknown,
done: (
err: Error | null,
@@ -153,7 +153,7 @@ if (
scopes,
},
});
return done(null, result.user, { ...result, client });
return done(null, result.user, { ...result, client, id_token: params.id_token });
} catch (err) {
return done(err, null);
}
+1
View File
@@ -147,6 +147,7 @@ router.post("auth.info", auth(), async (ctx: APIContext<T.AuthInfoReq>) => {
groups: await Promise.all(groups.map(presentGroup)),
groupUsers: groups.map((group) => presentGroupUser(group.groupUsers[0])),
collaborationToken: user.getCollaborationToken(),
id_token: ctx.state.auth.id_token,
availableTeams: uniqBy([...signedInTeams, ...availableTeams], "id").map(
(availableTeam) =>
presentAvailableTeam(
+2
View File
@@ -45,12 +45,14 @@ export enum AuthenticationType {
export type AuthenticationResult = AccountProvisionerResult & {
client: Client;
id_token?: string;
};
export type Authentication = {
user: User;
token?: string;
type?: AuthenticationType;
id_token?: string;
};
export type Pagination = {
+1 -1
View File
@@ -30,7 +30,7 @@ export function getSessionsInCookie(ctx: Context) {
export async function signIn(
ctx: Context,
service: string,
{ user, team, client, isNewTeam }: AuthenticationResult
{ user, team, client, isNewTeam, id_token }: AuthenticationResult
) {
if (team.isSuspended) {
return ctx.redirect("/?notice=team-suspended");
+4
View File
@@ -10,6 +10,10 @@ type Props = {
captureEvents?: "all" | "pointer" | "click";
};
/**
* EventBoundary is a component that prevents events from propagating to parent elements.
* This is useful for preventing clicks or other interactions from bubbling up the DOM tree.
*/
const EventBoundary: React.FC<Props> = ({
children,
className,
+12
View File
@@ -5,14 +5,26 @@ type JustifyValues = CSSProperties["justifyContent"];
type AlignValues = CSSProperties["alignItems"];
/**
* Flex is a styled component that provides a flexible box layout with convenient props.
* It simplifies the use of flexbox CSS properties with a clean, declarative API.
*/
const Flex = styled.div<{
/** Makes the component grow to fill available space */
auto?: boolean;
/** Changes flex direction to column */
column?: boolean;
/** Sets the align-items CSS property */
align?: AlignValues;
/** Sets the justify-content CSS property */
justify?: JustifyValues;
/** Enables flex-wrap */
wrap?: boolean;
/** Controls flex-shrink behavior */
shrink?: boolean;
/** Reverses the direction (row-reverse or column-reverse) */
reverse?: boolean;
/** Sets gap between flex items in pixels */
gap?: number;
}>`
display: flex;
+5
View File
@@ -11,6 +11,11 @@ type Props = {
className?: string;
};
/**
* Squircle is a component that renders a square with rounded corners (squircle shape).
* It's commonly used for app icons, avatars, and other UI elements where a softer
* square shape is desired.
*/
const Squircle: React.FC<Props> = ({
color,
size = 28,