mirror of
https://github.com/suitenumerique/meet.git
synced 2026-08-18 22:36:29 +00:00
🔒️(frontend) restrict transit_code exchange to embedded context
Only run the transit_code exchange flow when the app is loaded in an embedded context (i.e. inside an iframe). Combined with the CSP rules that will restrict which origins are allowed to embed the app, this gives us a client-side lever to control which integrations can actually use this authentication path.
This commit is contained in:
@@ -1,6 +1,9 @@
|
||||
import { fetchApi } from '@/api/fetchApi'
|
||||
import { setAccessToken } from '@/stores/accessToken'
|
||||
import { consumeTransitCodeFromFragment } from '../utils/transitCode'
|
||||
import {
|
||||
consumeTransitCodeFromFragment,
|
||||
isEmbedded,
|
||||
} from '../utils/transitCode'
|
||||
|
||||
type ApiAccessToken = {
|
||||
access_token: string
|
||||
@@ -28,6 +31,11 @@ const runInitialization = async (): Promise<void> => {
|
||||
return
|
||||
}
|
||||
|
||||
if (!isEmbedded()) {
|
||||
console.warn('Transit code ignored outside an embedded context')
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
const { access_token } = await exchangeAccessToken(code)
|
||||
setAccessToken(access_token)
|
||||
|
||||
@@ -23,9 +23,13 @@ export const TransitCodeGate = ({
|
||||
}) => {
|
||||
const hash = useHash()
|
||||
|
||||
// Latch the decision on the initial hash: the bootstrap scrubs the
|
||||
// fragment as soon as it starts, and the gate must not flip back to the
|
||||
// fast path while the exchange is still in flight.
|
||||
// Note: the exchange only happens in an embedding context. This check lives
|
||||
// in initializeAccessTokenFromFragment, the single funnel for all bootstrap paths.
|
||||
// The gate still mounts top-level to scrub the fragment, but bootstrap then resolves
|
||||
// immediately without exchanging.
|
||||
//
|
||||
// Latch the decision on the initial hash: bootstrap scrubs it immediately, and the
|
||||
// gate must not switch back to the fast path while the exchange is in flight.
|
||||
const [needsExchange] = useState(() => hasTransitCodeInFragment(hash))
|
||||
|
||||
if (!needsExchange) {
|
||||
|
||||
@@ -1,5 +1,18 @@
|
||||
const TRANSIT_CODE_FRAGMENT_PARAM = 'transit_code'
|
||||
|
||||
/**
|
||||
* Whether the app is rendered inside an embedding context (iframe).
|
||||
*
|
||||
* Comparing window references never throws, even when the parent is
|
||||
* cross-origin. Defaults to false outside a browser environment.
|
||||
*/
|
||||
export const isEmbedded = (): boolean => {
|
||||
if (typeof window === 'undefined') {
|
||||
return false
|
||||
}
|
||||
return window.self !== window.top
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether a URL fragment carries a transit code. Pure check, does not
|
||||
* consume anything.
|
||||
|
||||
Reference in New Issue
Block a user