Schema Analyzer calls don't have the refreshed token which causes 401 error · Issue #564 · api-platform/admin · GitHub
Skip to content

Schema Analyzer calls don't have the refreshed token which causes 401 error #564

Open

Description

@greggailly

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:
Screenshot 2024-05-31 at 14 11 12
These calls seem to be initiated by the Guesser Components to fetch the schema:
Screenshot 2024-05-31 at 15 35 15

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

  1. Clone Api Platform Demo repository
  2. Remove 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 Admin interface not rendering dropdown for Enum on HydraAdmin #494 (comment) doesn't seem to be the source as when using the normal parseHydraDocumentation problem 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

Activity

  1. greggailly commented on Jun 3, 2024

    @greggailly
    Author

    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

  2. greggailly commented on Jun 3, 2024

    @greggailly
    Author

    @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 !

  3. papppeter commented on Oct 2, 2024

    @papppeter

    Do you have a solution? it v4 is affected.

  4. papppeter commented on Oct 2, 2024

    @papppeter

    #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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions