WARNING TO BRAINSTORM ON PROPAGATING AUTH TO IFRAME DOMAIN (separate flow with its own OIDC clientId or using current token?)

This commit is contained in:
Thomas Ramé
2026-03-24 15:02:19 +01:00
parent 3e3ee7e698
commit 8c5352103a
3 changed files with 72 additions and 17 deletions
+2 -2
View File
@@ -51,8 +51,8 @@ LOGOUT_REDIRECT_URL=http://localhost:3000
OIDC_REDIRECT_ALLOWED_HOSTS="localhost:8083,localhost:3000"
OIDC_AUTH_REQUEST_EXTRA_PARAMS={"acr_values": "eidas1"}
# Store OIDC tokens in the session. Needed by search/ endpoint.
# OIDC_STORE_ACCESS_TOKEN = True
# Store OIDC tokens in the session. Needed by search/ endpoint and encryption service.
OIDC_STORE_ACCESS_TOKEN = True
# OIDC_STORE_REFRESH_TOKEN = True # Store the encrypted refresh token in the session.
# Must be a valid Fernet key (32 url-safe base64-encoded bytes)
+29
View File
@@ -252,6 +252,35 @@ class UserViewSet(
self.serializer_class(request.user, context=context).data
)
@drf.decorators.action(
detail=False,
methods=["get"],
url_name="get-access-token",
url_path="get-access-token",
permission_classes=[permissions.IsAuthenticated],
)
def get_access_token(self, request):
"""
WARNING: Temporary endpoint — to be removed.
TODO: Find a better way to propagate the OIDC access token to the frontend
so it can be passed to the VaultClient encryption library.
We should also consider having ProConnect flow directly on interface.encryption,
so it can obtain its own valid token when opened in a new tab (not as an iframe).
Returns the OIDC access token stored in the Django session.
Requires OIDC_STORE_ACCESS_TOKEN=True in settings.
"""
access_token = request.session.get("oidc_access_token")
if not access_token:
return drf.response.Response(
{"detail": "No access token available in session."},
status=404,
)
return drf.response.Response({"access_token": access_token})
class ResourceAccessViewsetMixin:
"""Mixin with methods common to all access viewsets."""
@@ -193,19 +193,39 @@ export function VaultClientProvider({
return;
}
// In Docs, auth is cookie-based. The vault in dev mode (no VITE_JWKS_URL)
// falls back to the declared userId. In production, pass a real JWT.
// TODO: Pass real ProConnect JWT when available.
client.setAuthContext({
token: 'session-cookie-auth',
userId: user.id,
});
let cancelled = false;
setIsLoading(true);
async function setupAuth() {
// Fetch the OIDC access token from the Django session.
// WARNING: This uses a temporary endpoint (get-access-token) — see the
// backend TODO for finding a better way to propagate the access token.
let token = user!.id; // fallback: userId (vault dev mode without JWKS)
client
.hasKeys()
.then(async ({ hasKeys: exists }) => {
try {
const response = await fetch(
`${process.env.NEXT_PUBLIC_API_ORIGIN || ''}/api/v1.0/users/get-access-token/`,
{ credentials: 'include' },
);
if (response.ok) {
const data = await response.json();
if (data.access_token) {
token = data.access_token;
}
}
} catch {
// Endpoint not available — fall back to userId for dev mode
}
if (cancelled) return;
client.setAuthContext({ token, userId: user!.id });
setIsLoading(true);
try {
const { hasKeys: exists } = await client.hasKeys();
setHasKeys(exists);
if (exists) {
@@ -214,12 +234,18 @@ export function VaultClientProvider({
}
setIsReady(true);
setIsLoading(false);
})
.catch((err) => {
} catch (err) {
setError((err as Error).message);
} finally {
setIsLoading(false);
});
}
}
void setupAuth();
return () => {
cancelled = true;
};
}, [clientInitialized, authenticated, user?.id]);
const refreshKeyState = useCallback(async () => {