Schema Analyzer calls don't have the refreshed token which causes 401 error
API Platform version(s) affected: api: 3.3, admin: 3.4.6
Description
When accessing a resource from the admin, several extra calls seem to be made on top of the main call fetching the data:
These calls seem to be initiated by the Guesser Components to fetch the schema:
These calls do include a JWT but this token is not refreshed if expired. The JWT in the "main" call is correctly updated.
How to reproduce
- Clone Api Platform Demo repository
- Remove <Resource> components so that the Guesser components do their job
Possible Solution
n/a
Additional Context
- Code is very close to the Demo:
// Admin.jsx
const apiDocumentationParser = (session) => async () => {
try {
return await parseHydraDocumentationWithEnums(ENTRYPOINT, {
headers: {
Authorization: `Bearer ${session?.accessToken}`,
},
});
} catch (result) {
// @ts-ignore
const { api, response, status } = result;
if (status !== 401 || !response) {
throw result;
}
return {
api,
response,
status,
};
}
};
const AdminUI = ({ children, session }) => {
const dataProvider = useRef();
const { docType } = useContext(DocContext);
dataProvider.current = hydraDataProvider({
entrypoint: ENTRYPOINT,
httpClient: (url, options = {}) => fetchHydra(url, {
...options,
headers: {
Authorization: `Bearer ${session?.accessToken}`,
},
}),
apiDocumentationParser: apiDocumentationParser(session),
});
return docType === "hydra" ? (
<HydraAdmin
requireAuth
authProvider={authProvider}
// @ts-ignore
dataProvider={dataProvider.current}
entrypoint={window.origin}
i18nProvider={i18nProvider}
layout={MyLayout}
>
{!!children && children}
</HydraAdmin>
) : (
<OpenApiAdmin
requireAuth
authProvider={authProvider}
// @ts-ignore
dataProvider={dataProvider.current}
entrypoint={window.origin}
docEntrypoint={`${window.origin}/docs.json`}
i18nProvider={i18nProvider}
layout={MyLayout}
>
{!!children && children}
</OpenApiAdmin>
);
};
const AdminWithContext = ({ session }) => {
const [docType, setDocType] = useState(
store.getItem("docType", "hydra"),
);
return (
<DocContext.Provider
value={{
docType,
setDocType,
}}>
<AdminUI session={session}>
// No Resources defined here unlike in the demo repo
</AdminUI>
</DocContext.Provider>
);
};
- parseHydraDocumentationWithEnums is based on https://github.com/api-platform/admin/issues/494#issuecomment-1427746210 doesn't seem to be the source as when using the normal
parseHydraDocumentationproblem remains. - Calls are made every time we access the resource from the admin if no ApiFilter is defined in the API
- If ApiFilter is defined in the API then calls are only made the first time we try to access the resource. If the resource is not accessed at least once before the initial token expires the problem remains
Issue seems to be coming from the api-doc-parser where the getParameters function is returned for each Resource with the token saved into it. Since parseHydraDocumentation is only called once when the page is loaded the JWT is never updated in the resource function call.
resource.getParameters = (): Promise<Parameter[]> => getParameters(resource, options);
https://github.com/api-platform/api-doc-parser/blob/e8b49f2b452c4a19fab5eea86ec742c8201d381f/src/hydra/parseHydraDocumentation.ts#L475-L476
@dunglas would such a change to the getParameters callback be accepeted ? Adding a "in_options" argument to eventually override at runtime the headers that can be sent to fetch resource parameters.
resource.getParameters = (in_options: RequestInitExtended = {}): Promise<Parameter[]> =>
getParameters(resource, {...options, ...in_options});
If yes then to be discussed, the schemaAnalyzer could be modified to take a new argument with the options.
export const resolveSchemaParameters = (schema: Resource, options: RequestInitExtended = {} ) => {
if (!schema.parameters || !schema.getParameters) {
return Promise.resolve([]);
}
return !schema.parameters.length
? schema.getParameters(options)
: Promise.resolve(schema.parameters);
};
};
Options (with Authentication headers) could then either be passed down from the FilterGuesser (and other Guessers) or (less likely I guess) fetched directly in the schemaAnalyzer (using local storage maybe ?).
Unless you see another solution to have the updated tokens passed down to the getParameter requests !
Do you have a solution? it v4 is affected.
https://github.com/api-platform/admin/issues/578 helped me to solve my issue. i created a custom parser where i did set the proper headers for authentication. but any better idea is wellcome.