0

I try to allow JWT introspection on my oidc provider, but it always results to an { "active": false }. I precise that i don't encounter problem for opaque introspection and I turned on the feature jwtIntrospection on the oidc configuration.

JWT payload example that return active false :

{
  "realm": "aq",
  "last_password_update": null,
  "jti": "pVMmyVTjmzVqLsl-9p5Ms",
  "sub": "953b49e3-14ee-4278-b818-1666fb0c1f67",
  "iat": 1707926210,
  "exp": 1707928010,
  "client_id": "953b49e3-14ee-4278-b818-1666fb0c1f67",
  "iss": "http://localhost:3080/op",
  "aud": "http://localhost:3080/api/v1/"
}

Introspect response when it's an opaque token :

{
  "active": true,
  "realm": "aq",
  "invitation_token": null,
  "last_password_update": null,
  "client_id": "953b49e3-14ee-4278-b818-1666fb0c1f67",
  "exp": 1707927912,
  "iat": 1707926112,
  "iss": "http://localhost:3080/op",
  "token_type": "Bearer"
}

Am I missing something ? Thanks!

EDIT : oidc configuration and token introspection

  private static oidcConfiguration = async (): Promise<Configuration> => ({
    acrValues: getAcrPolicies().map((acrPolicy) => acrPolicy.acrValue),
    conformIdTokenClaims: false,
    extraClientMetadata: {
      properties: [
        'accessTokenLifetime',
        'cancel_logout_redirect_uris',
        'consumedResources',
        'isIntrospectionAllowed',
        'managedResource',
        'pkceRequired',
        'refreshTokenTotalLifetime',
        'serviceId',
      ],
    },
    extraParams: ['sign_in_only', 'sign_up', 'invitation_token', 'sub', 'login_hint'],
    extraTokenClaims,
    scopes: getScopePolicies().map((scope) => scope.scope),
    clients: getClients(),
    cookies: {
      names: {
        interaction: 'op_interaction',
        resume: 'op_interaction_resume',
        session: 'op_session',
        state: 'op_state',
      },
      long: {
        httpOnly: true,
        overwrite: true,
        signed: true,
        secure: process.env.APP_ENV !== 'local',
        sameSite: 'none',
        path: process.env.OP_PATH,
      },
      short: {
        httpOnly: true,
        overwrite: true,
        signed: true,
        secure: process.env.APP_ENV !== 'local',
        sameSite: 'none',
        path: process.env.OP_PATH,
      },
      keys: getMainConfiguration().cookieKeys,
    },
    interactions: {
      policy: await OidcService.getPolicy(),
      url(_, interaction: Interaction) {
        return concatUrl('/op', '/interaction', interaction.uid);
      },
    },
    routes: {
      authorization: '/auth',
      code_verification: '/device',
      device_authorization: '/device/auth',
      end_session: '/session/end',
      introspection: '/token/introspection',
      jwks: '/jwks',
      pushed_authorization_request: '/request',
      registration: '/reg',
      revocation: '/token/revocation',
      token: '/token',
      userinfo: '/me',
    },
    features: {
      // Node OIDC Provider parameters
      backchannelLogout: { enabled: true },
      claimsParameter: { enabled: false },
      clientCredentials: { enabled: true },
      dPoP: { enabled: false },
      devInteractions: { enabled: false },
      deviceFlow: { enabled: false },
      encryption: { enabled: false },
      introspection: {
        enabled: true,
        allowedPolicy: (ctx, client) => {
          const clientMetadata = client.metadata();

          return clientMetadata.isIntrospectionAllowed;
        },
      },
      jwtIntrospection: { enabled: true, ack: 'draft-10' },
      jwtResponseModes: { enabled: false },
      jwtUserinfo: { enabled: false },
      mTLS: { enabled: false },
      pushedAuthorizationRequests: { enabled: false },
      registration: { enabled: false },
      registrationManagement: { enabled: false },
      requestObjects: {},
      resourceIndicators: {
        // enable = true, to activate resourceIndicator
        enabled: true,
        // defaultResource = undefined, to return an access token without audience when no resource is explicitly request during AT request
        defaultResource: (ctx) => undefined,
        getResourceServerInfo: async (ctx, resourceIndicator, client) => {
          return OidcService.getResourceServerInfo(ctx, resourceIndicator, client);
        },
        useGrantedResource: () => false,
      },
      revocation: { enabled: true },
      rpInitiatedLogout: {
        enabled: true,
        logoutSource: async (ctx: KoaContextWithOIDC, form: string): Promise<void> => {
          ctx.body = await logoutPage(ctx, form);
        },
        postLogoutSuccessSource: async (ctx: KoaContextWithOIDC): Promise<void> => {
          ctx.body = await postLogoutSuccessPage(ctx);
        },
      },
      userinfo: { enabled: true },
      webMessageResponseMode: { enabled: false },
    },
    findAccount: (ctx: KoaContextWithOIDC, sub: string): any => AccountService.findAccount(ctx, sub),
    ttl: ttlConfiguration,
    pkce: {
      methods: ['S256'],
      required: (ctx, client) => {
        return client.pkceRequired !== false;
      },
    },
    renderError: (ctx, out, error) => {
      const err = error as errorsType.OIDCProviderError;
      const clientId = ctx.oidc?.client?.clientId;

      return RenderPageUtils.renderError(ctx.req as Request, ctx.res as Response, {
        statusCode: err?.statusCode ? err.statusCode.toString() : '500',
        reason: out.error_description,
        clientId,
      });
    },
  });

and my token introspection (performed at an express route middleware) :

const client = await getClientAPI();
const instrospectResponse = await client.introspect(accessToken, 'access_token');

client value :

{
  authorization_signed_response_alg: 'RS256',
  client_id: 'client-api',
  grant_types: [
    'authorization_code'
  ],
  id_token_signed_response_alg: 'ES256',
  introspection_endpoint_auth_method: 'private_key_jwt',
  introspection_endpoint_auth_signing_alg: 'ES256',
  introspection_signed_response_alg: 'ES256',
  response_types: [
    'code'
  ],
  revocation_endpoint_auth_method: 'private_key_jwt',
  revocation_endpoint_auth_signing_alg: 'ES256',
  token_endpoint_auth_method: 'private_key_jwt',
  token_endpoint_auth_signing_alg: 'ES256'
}
7
  • This is documented behaviour as per github.com/panva/node-oidc-provider/blob/v8.x/docs/… Commented Feb 14, 2024 at 17:21
  • Can you share your JWT Introspection code? Commented Feb 14, 2024 at 18:11
  • @BenchVue sure, i have generated one : eyJhbGciOiJFUzI1NiIsInR5cCI6ImF0K2p3dCIsImtpZCI6Im9wLWtleS0yMDIwMDcwMyJ9.eyJyZWFsbSI6ImFxIiwibGFzdF9wYXNzd29yZF91cGRhdGUiOm51bGwsImp0aSI6IkpzNlViYWt1R1I1Mmdic1lRblFCUSIsInN1YiI6Ijk1M2I0OWUzLTE0ZWUtNDI3OC1iODE4LTE2NjZmYjBjMWY2NyIsImlhdCI6MTcwNzk5MTc3OCwiZXhwIjoxNzA3OTkzNTc4LCJjbGllbnRfaWQiOiI5NTNiNDllMy0xNGVlLTQyNzgtYjgxOC0xNjY2ZmIwYzFmNjciLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjMwODAvb3AiLCJhdWQiOiJodHRwOi8vbG9jYWxob3N0OjMwODAvYXBpL3YxLyJ9.Ktj7XVcJiY5SDoq_i1dIIL_5KYorEzW5MX2rQsEH-rSGHXd0QTqkOauX_4zN1Ppx_os8TbP76yld83KYVj6B0A Commented Feb 15, 2024 at 10:12
  • It is JWT, My question do you have source of code for "localhost:3080" server and Introspection call source of code. (node.js or other language) Commented Feb 15, 2024 at 11:11
  • 1
    @BenchVue oh okay, unfortunately I cannot share you all of it because I'm working for a company... but I can edit my post to add our oidc configuration and how I'm making the introspection Commented Feb 15, 2024 at 14:21

0

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.