{"record":{"id":"e33c5cf1a8cb6244","repo":"quarkusio/quarkus","slug":"refresh-token-is-null","errorCode":null,"errorMessage":"Refresh token is null","messagePattern":"Refresh token is null","errorType":"exception","errorClass":"OidcClientException","httpStatus":null,"severity":"error","filePath":"extensions/oidc-client/runtime/src/main/java/io/quarkus/oidc/client/runtime/OidcClientImpl.java","lineNumber":118,"sourceCode":"        this.clientSecret = clientCredentials.clientSecret;\n        this.clientAssertionProvider = clientCredentials.clientAssertionProvider;\n    }\n\n    @Override\n    public Uni<Tokens> getTokens(Map<String, String> additionalGrantParameters) {\n        checkClosed();\n        if (tokenGrantParams == null) {\n            throw new OidcClientException(\n                    \"Only 'refresh_token' grant is supported, please call OidcClient#refreshTokens method instead\");\n        }\n        return getJsonResponse(OidcEndpoint.Type.TOKEN, tokenGrantParams, additionalGrantParameters, Operation.GET);\n    }\n\n    @Override\n    public Uni<Tokens> refreshTokens(String refreshToken, Map<String, String> additionalGrantParameters) {\n        checkClosed();\n        if (refreshToken == null) {\n            throw new OidcClientException(\"Refresh token is null\");\n        }\n        MultiMap refreshGrantParams = copyMultiMap(commonRefreshGrantParams);\n        refreshGrantParams.add(OidcConstants.REFRESH_TOKEN_VALUE, refreshToken);\n        return getJsonResponse(OidcEndpoint.Type.TOKEN, refreshGrantParams, additionalGrantParameters, Operation.REFRESH);\n    }\n\n    @Override\n    public Uni<Boolean> revokeAccessToken(String accessToken, Map<String, String> additionalParameters) {\n        checkClosed();\n        if (accessToken == null) {\n            throw new OidcClientException(\"Access token is null\");\n        }\n        OidcRequestContextProperties requestProps = getRequestProps(null);\n\n        if (tokenRevokeUri != null) {\n            MultiMap tokenRevokeParams = MultiMap.caseInsensitiveMultiMap();\n            tokenRevokeParams.set(OidcConstants.REVOCATION_TOKEN, accessToken);\n            return withAsyncCredentials().flatMap(asyncCredentials -> postRequest(requestProps,","sourceCodeStart":100,"sourceCodeEnd":136,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/extensions/oidc-client/runtime/src/main/java/io/quarkus/oidc/client/runtime/OidcClientImpl.java#L100-L136","documentation":"OidcClientImpl.refreshTokens() requires a non-null refresh token string because it is sent as the refresh_token grant parameter. A null argument fails fast with an OidcClientException rather than producing a broken token request.","triggerScenarios":"Calling oidcClient.refreshTokens(null, additionalGrantParameters) — typically when the stored/previous Tokens had no refresh token (e.g. the OP did not issue one) and null was propagated.","commonSituations":"Identity providers that omit refresh_token in responses; persisting Tokens without checking refresh token availability; code assuming a refresh token always exists.","solutions":["Check the refresh token for null/blank before calling refreshTokens() and re-authenticate (or call getTokens()) if absent.","Persist Tokens.refreshToken only when present and handle the absent case in your token store.","Verify the OIDC provider actually issues refresh tokens (offline_access scope or equivalent) for the configured grant."],"exampleFix":"// before\nTokens t = oidcClient.refreshTokens(current.getRefreshToken(), Map.of()).await().indefinitely();\n\n// after\nif (current.getRefreshToken() != null) {\n    Tokens t = oidcClient.refreshTokens(current.getRefreshToken(), Map.of()).await().indefinitely();\n} else {\n    Tokens t = oidcClient.getTokens().await().indefinitely();\n}","handlingStrategy":"type-guard","validationCode":"String rt = tokens.getRefreshToken();\nif (rt == null || rt.isBlank()) {\n    throw new IllegalStateException(\"No refresh token available; re-authentication required\");\n}","typeGuard":"boolean hasRefreshToken(Tokens t) { return t != null && t.getRefreshToken() != null && !t.getRefreshToken().isBlank(); }","tryCatchPattern":"try {\n    return client.refreshTokens(rt, params);\n} catch (OidcClientException e) {\n    if (e.getMessage().contains(\"Refresh token is null\")) {\n        return reauthenticate();\n    }\n    throw e;\n}","preventionTips":["Request scopes that yield refresh tokens (e.g. offline_access).","Never persist Tokens without checking refresh token presence.","Default to full re-authentication when no refresh token exists."],"tags":["oidc-client","refresh-token","null-check"],"backgroundTag":"missing-refresh-token","analyzedSha":"e1c734241f34c7919086ceb4c9262b4a58f6de44","analyzedAt":"2026-09-05T17:01:29.979Z","contentChangedAt":"2026-09-05T17:01:29.979Z","schemaVersion":2},"datasetVersion":"2026-09-12T22:17:10.623Z"}