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:
@@ -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)
|
||||
|
||||
@@ -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."""
|
||||
|
||||
+41
-15
@@ -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 () => {
|
||||
|
||||
Reference in New Issue
Block a user