Preflight checklist
Ory Network Project
No response
Describe the bug
Kratos fails to verify Telegram OIDC tokens with the following error:
failed to verify signature: fetching keys oidc: failed to decode keys:
got Content-Type = application/json, but could not unmarshal as JSON:
go-jose/go-jose: unsupported elliptic curve 'secp256k1'
Telegram recently added an ES256K key (crv: secp256k1, kid: oidc-es256k-1)
to their JWKS at https://oauth.telegram.org/.well-known/jwks.json. go-jose
fails to unmarshal the entire JWK set when it encounters this unsupported curve,
even though the token is signed with the RS256 key (kid: oidc-1) which is valid.
All Telegram OIDC logins are broken as a result.
Reproducing the bug
- Configure a generic OIDC provider with issuer_url: https://oauth.telegram.org
- Attempt login via Telegram
- Kratos logs the error above when verifying the id_token signature
Relevant log output
{
"error": {
"debug": "",
"message": "The request was malformed or contained invalid parameters",
"reason": "failed to verify signature: fetching keys oidc: failed to decode keys: got Content-Type = application/json, but could not unmarshal as JSON: go-jose/go-jose: unsupported elliptic curve 'secp256k1' {\n \"keys\": [\n {\n \"alg\": \"RS256\",\n \"e\": \"AQAB\",\n \"ext\": true,\n \"key_ops\": [\n \"verify\"\n ],\n \"kty\": \"RSA\",\n \"n\": \"5RneLtsKvVcxdv6gu6gxEQu30Cru5NiMQnY6SNr9ZyZFZ4ya-pfHNuaZXJ6QPG0JSFwoxeOkEO2-eZN_REVPm448PvjjsR1eQdZ5QpEkNxnItFcmxkHH91v5cgf52_EI9BGO-MT6f1vaBSg3uWHFlDxI7J2AYxNvd1_Nf3TkgrrR7gyJFTmEIai5RefGnA0KGNYDlRIGUzrz2F05n6gTaHFT_iHL5UHatTZA4GCiUSjIOuwqu5pE5uZge20TFv3cxXMQaFw_xv1pgQt_Rq8eoCN7TS0RQ0zjWKiad-W286BcFectXsUm03p5Nq_kY4mf_7rqwX_B8yy_bBreyKn7RQ\",\n \"kid\": \"oidc-1\"\n },\n {\n \"alg\": \"ES256\",\n \"kty\": \"EC\",\n \"x\": \"ahVYrohhX6YA7w0P2gUNSwMFbaabCgBZFkeq9bWdmwU\",\n \"y\": \"Ea8nKJ34VQMA7zv8aYDfzcBhXEjnWQ9C06jVke_eUV0\",\n \"crv\": \"P-256\",\n \"kid\": \"oidc-es256-1\",\n \"use\": \"sig\"\n },\n {\n \"alg\": \"EdDSA\",\n \"crv\": \"Ed25519\",\n \"x\": \"i6BEafXMEe4osXgUTffpKAm6Cn6F2bhqPZoclunTAV4\",\n \"kty\": \"OKP\",\n \"kid\": \"oidc-eddsa-1\",\n \"use\": \"sig\"\n },\n {\n \"alg\": \"ES256K\",\n \"kty\": \"EC\",\n \"x\": \"vsk5i5YJu8H_VPL7DWTgVGXBPrqgkyNmYvfgOrVut38\",\n \"y\": \"Mrg56tBhVeorHPXK1LbTX2jP7rEqOHIatM96HFzVMIU\",\n \"crv\": \"secp256k1\",\n \"kid\": \"oidc-es256k-1\",\n \"use\": \"sig\"\n }\n ]\n}",
"stack_trace": "\ngithub.com/ory/kratos/selfservice/strategy/oidc.(*ProviderGenericOIDC).verifyAndDecodeClaimsWithProvider\n\t/project/selfservice/strategy/oidc/provider_generic_oidc.go:103\ngithub.com/ory/kratos/selfservice/strategy/oidc.(*ProviderGenericOIDC).claimsFromIDToken\n\t/project/selfservice/strategy/oidc/provider_generic_oidc.go:190\ngithub.com/ory/kratos/selfservice/strategy/oidc.(*ProviderGenericOIDC).Claims\n\t/project/selfservice/strategy/oidc/provider_generic_oidc.go:123\ngithub.com/ory/kratos/selfservice/strategy/oidc.(*Strategy).HandleCallback\n\t/project/selfservice/strategy/oidc/strategy.go:506\ngithub.com/ory/kratos/selfservice/strategy.disabledWriter\n\t/project/selfservice/strategy/handler.go:26\ngithub.com/ory/kratos/selfservice/strategy/oidc.(*Strategy).RegisterPublicRoutes.IsDisabled.func1\n\t/project/selfservice/strategy/handler.go:31\nnet/http.HandlerFunc.ServeHTTP\n\t/usr/local/go/src/net/http/server.go:2286\ngithub.com/prometheus/client_golang/prometheus/promhttp.InstrumentHandlerResponseSize.func1\n\t/go/pkg/mod/github.com/prometheus/client_golang@v1.23.0/prometheus/promhttp/instrument_server.go:296\nnet/http.HandlerFunc.ServeHTTP\n\t/usr/local/go/src/net/http/server.go:2286\ngithub.com/prometheus/client_golang/prometheus/promhttp.InstrumentHandlerCounter.func1\n\t/go/pkg/mod/github.com/prometheus/client_golang@v1.23.0/prometheus/promhttp/instrument_server.go:147\nnet/http.HandlerFunc.ServeHTTP\n\t/usr/local/go/src/net/http/server.go:2286\ngithub.com/prometheus/client_golang/prometheus/promhttp.InstrumentHandlerDuration.func1\n\t/go/pkg/mod/github.com/prometheus/client_golang@v1.23.0/prometheus/promhttp/instrument_server.go:97\nnet/http.HandlerFunc.ServeHTTP\n\t/usr/local/go/src/net/http/server.go:2286\ngithub.com/prometheus/client_golang/prometheus/promhttp.InstrumentHandlerDuration.func2\n\t/go/pkg/mod/github.com/prometheus/client_golang@v1.23.0/prometheus/promhttp/instrument_server.go:109\nnet/http.HandlerFunc.ServeHTTP\n\t/usr/local/go/src/net/http/server.go:2286\ngithub.com/prometheus/client_golang/prometheus/promhttp.InstrumentHandlerRequestSize.func1\n\t/go/pkg/mod/github.com/prometheus/client_golang@v1.23.0/prometheus/promhttp/instrument_server.go:243\nnet/http.HandlerFunc.ServeHTTP\n\t/usr/local/go/src/net/http/server.go:2286\ngithub.com/ory/x/prometheusx.(*HTTPMetrics).Instrument.(*HTTPMetrics).instrumentHandlerStatusBucket.func1\n\t/project/oryx/prometheusx/metrics.go:112\nnet/http.HandlerFunc.ServeHTTP\n\t/usr/local/go/src/net/http/server.go:2286\nnet/http.(*ServeMux).ServeHTTP\n\t/usr/local/go/src/net/http/server.go:2828\ngithub.com/ory/x/httprouterx.(*router).ServeHTTP\n\t/project/oryx/httprouterx/router.go:113\ngithub.com/ory/kratos/cmd/daemon.servePublic.SpanNameRecorderMiddleware.func4\n\t/project/oryx/otelx/middleware.go:37\nnet/http.HandlerFunc.ServeHTTP\n\t/usr/local/go/src/net/http/server.go:2286\ngithub.com/ory/nosurf.(*CSRFHandler).handleSuccess\n\t/go/pkg/mod/github.com/ory/nosurf@v1.2.7/handler.go:234\ngithub.com/ory/nosurf.(*CSRFHandler).ServeHTTP\n\t/go/pkg/mod/github.com/ory/nosurf@v1.2.7/handler.go:185\ngithub.com/urfave/negroni.(*Negroni).UseHandler.Wrap.func1\n\t/go/pkg/mod/github.com/urfave/negroni@v1.0.0/negroni.go:46\ngithub.com/urfave/negroni.HandlerFunc.ServeHTTP\n\t/go/pkg/mod/github.com/urfave/negroni@v1.0.0/negroni.go:29\ngithub.com/urfave/negroni.middleware.ServeHTTP\n\t/go/pkg/mod/github.com/urfave/negroni@v1.0.0/negroni.go:38\ngithub.com/ory/kratos/cmd/daemon.servePublic.func1\n\t/project/cmd/daemon/serve.go:83\ngithub.com/urfave/negroni.HandlerFunc.ServeHTTP\n\t/go/pkg/mod/github.com/urfave/negroni@v1.0.0/negroni.go:29\ngithub.com/urfave/negroni.middleware.ServeHTTP\n\t/go/pkg/mod/github.com/urfave/negroni@v1.0.0/negroni.go:38\ngithub.com/ory/x/metricsx.(*Service).ServeHTTP\n\t/project/oryx/metricsx/middleware.go:281",
"status": "Bad Request",
"status_code": 400
},
}
Relevant configuration
oidc:
config:
- id: telegram
label: "Telegram"
provider: generic
client_id: xxxxx
client_secret: xxxxxxxxxxxx
issuer_url: https://oauth.telegram.org
pkce: "never"
mapper_url: xxxxxxxxx
scope:
- openid
- profile
Version
v26.2.0
On which operating system are you observing this issue?
Linux
In which environment are you deploying?
Kubernetes with Helm
Additional Context
This is a regression. No Kratos or provider config was changed on our side.
Telegram added the ES256K key to support TON blockchain wallet authentication,
which is unrelated to standard OIDC flows.
The fix likely belongs in go-jose (graceful skip of unknown curve keys) or in
Kratos as a pre-filter step before passing the JWK set to go-jose. Worth checking
whether upgrading to new version of go-jose already resolves this behavior.
Affected JWKS entry:
{"alg":"ES256K","kty":"EC","crv":"secp256k1","kid":"oidc-es256k-1","use":"sig"}
Preflight checklist
Ory Network Project
No response
Describe the bug
Kratos fails to verify Telegram OIDC tokens with the following error:
failed to verify signature: fetching keys oidc: failed to decode keys:
got Content-Type = application/json, but could not unmarshal as JSON:
go-jose/go-jose: unsupported elliptic curve 'secp256k1'
Telegram recently added an ES256K key (crv: secp256k1, kid: oidc-es256k-1)
to their JWKS at https://oauth.telegram.org/.well-known/jwks.json. go-jose
fails to unmarshal the entire JWK set when it encounters this unsupported curve,
even though the token is signed with the RS256 key (kid: oidc-1) which is valid.
All Telegram OIDC logins are broken as a result.
Reproducing the bug
Relevant log output
{ "error": { "debug": "", "message": "The request was malformed or contained invalid parameters", "reason": "failed to verify signature: fetching keys oidc: failed to decode keys: got Content-Type = application/json, but could not unmarshal as JSON: go-jose/go-jose: unsupported elliptic curve 'secp256k1' {\n \"keys\": [\n {\n \"alg\": \"RS256\",\n \"e\": \"AQAB\",\n \"ext\": true,\n \"key_ops\": [\n \"verify\"\n ],\n \"kty\": \"RSA\",\n \"n\": \"5RneLtsKvVcxdv6gu6gxEQu30Cru5NiMQnY6SNr9ZyZFZ4ya-pfHNuaZXJ6QPG0JSFwoxeOkEO2-eZN_REVPm448PvjjsR1eQdZ5QpEkNxnItFcmxkHH91v5cgf52_EI9BGO-MT6f1vaBSg3uWHFlDxI7J2AYxNvd1_Nf3TkgrrR7gyJFTmEIai5RefGnA0KGNYDlRIGUzrz2F05n6gTaHFT_iHL5UHatTZA4GCiUSjIOuwqu5pE5uZge20TFv3cxXMQaFw_xv1pgQt_Rq8eoCN7TS0RQ0zjWKiad-W286BcFectXsUm03p5Nq_kY4mf_7rqwX_B8yy_bBreyKn7RQ\",\n \"kid\": \"oidc-1\"\n },\n {\n \"alg\": \"ES256\",\n \"kty\": \"EC\",\n \"x\": \"ahVYrohhX6YA7w0P2gUNSwMFbaabCgBZFkeq9bWdmwU\",\n \"y\": \"Ea8nKJ34VQMA7zv8aYDfzcBhXEjnWQ9C06jVke_eUV0\",\n \"crv\": \"P-256\",\n \"kid\": \"oidc-es256-1\",\n \"use\": \"sig\"\n },\n {\n \"alg\": \"EdDSA\",\n \"crv\": \"Ed25519\",\n \"x\": \"i6BEafXMEe4osXgUTffpKAm6Cn6F2bhqPZoclunTAV4\",\n \"kty\": \"OKP\",\n \"kid\": \"oidc-eddsa-1\",\n \"use\": \"sig\"\n },\n {\n \"alg\": \"ES256K\",\n \"kty\": \"EC\",\n \"x\": \"vsk5i5YJu8H_VPL7DWTgVGXBPrqgkyNmYvfgOrVut38\",\n \"y\": \"Mrg56tBhVeorHPXK1LbTX2jP7rEqOHIatM96HFzVMIU\",\n \"crv\": \"secp256k1\",\n \"kid\": \"oidc-es256k-1\",\n \"use\": \"sig\"\n }\n ]\n}", "stack_trace": "\ngithub.com/ory/kratos/selfservice/strategy/oidc.(*ProviderGenericOIDC).verifyAndDecodeClaimsWithProvider\n\t/project/selfservice/strategy/oidc/provider_generic_oidc.go:103\ngithub.com/ory/kratos/selfservice/strategy/oidc.(*ProviderGenericOIDC).claimsFromIDToken\n\t/project/selfservice/strategy/oidc/provider_generic_oidc.go:190\ngithub.com/ory/kratos/selfservice/strategy/oidc.(*ProviderGenericOIDC).Claims\n\t/project/selfservice/strategy/oidc/provider_generic_oidc.go:123\ngithub.com/ory/kratos/selfservice/strategy/oidc.(*Strategy).HandleCallback\n\t/project/selfservice/strategy/oidc/strategy.go:506\ngithub.com/ory/kratos/selfservice/strategy.disabledWriter\n\t/project/selfservice/strategy/handler.go:26\ngithub.com/ory/kratos/selfservice/strategy/oidc.(*Strategy).RegisterPublicRoutes.IsDisabled.func1\n\t/project/selfservice/strategy/handler.go:31\nnet/http.HandlerFunc.ServeHTTP\n\t/usr/local/go/src/net/http/server.go:2286\ngithub.com/prometheus/client_golang/prometheus/promhttp.InstrumentHandlerResponseSize.func1\n\t/go/pkg/mod/github.com/prometheus/client_golang@v1.23.0/prometheus/promhttp/instrument_server.go:296\nnet/http.HandlerFunc.ServeHTTP\n\t/usr/local/go/src/net/http/server.go:2286\ngithub.com/prometheus/client_golang/prometheus/promhttp.InstrumentHandlerCounter.func1\n\t/go/pkg/mod/github.com/prometheus/client_golang@v1.23.0/prometheus/promhttp/instrument_server.go:147\nnet/http.HandlerFunc.ServeHTTP\n\t/usr/local/go/src/net/http/server.go:2286\ngithub.com/prometheus/client_golang/prometheus/promhttp.InstrumentHandlerDuration.func1\n\t/go/pkg/mod/github.com/prometheus/client_golang@v1.23.0/prometheus/promhttp/instrument_server.go:97\nnet/http.HandlerFunc.ServeHTTP\n\t/usr/local/go/src/net/http/server.go:2286\ngithub.com/prometheus/client_golang/prometheus/promhttp.InstrumentHandlerDuration.func2\n\t/go/pkg/mod/github.com/prometheus/client_golang@v1.23.0/prometheus/promhttp/instrument_server.go:109\nnet/http.HandlerFunc.ServeHTTP\n\t/usr/local/go/src/net/http/server.go:2286\ngithub.com/prometheus/client_golang/prometheus/promhttp.InstrumentHandlerRequestSize.func1\n\t/go/pkg/mod/github.com/prometheus/client_golang@v1.23.0/prometheus/promhttp/instrument_server.go:243\nnet/http.HandlerFunc.ServeHTTP\n\t/usr/local/go/src/net/http/server.go:2286\ngithub.com/ory/x/prometheusx.(*HTTPMetrics).Instrument.(*HTTPMetrics).instrumentHandlerStatusBucket.func1\n\t/project/oryx/prometheusx/metrics.go:112\nnet/http.HandlerFunc.ServeHTTP\n\t/usr/local/go/src/net/http/server.go:2286\nnet/http.(*ServeMux).ServeHTTP\n\t/usr/local/go/src/net/http/server.go:2828\ngithub.com/ory/x/httprouterx.(*router).ServeHTTP\n\t/project/oryx/httprouterx/router.go:113\ngithub.com/ory/kratos/cmd/daemon.servePublic.SpanNameRecorderMiddleware.func4\n\t/project/oryx/otelx/middleware.go:37\nnet/http.HandlerFunc.ServeHTTP\n\t/usr/local/go/src/net/http/server.go:2286\ngithub.com/ory/nosurf.(*CSRFHandler).handleSuccess\n\t/go/pkg/mod/github.com/ory/nosurf@v1.2.7/handler.go:234\ngithub.com/ory/nosurf.(*CSRFHandler).ServeHTTP\n\t/go/pkg/mod/github.com/ory/nosurf@v1.2.7/handler.go:185\ngithub.com/urfave/negroni.(*Negroni).UseHandler.Wrap.func1\n\t/go/pkg/mod/github.com/urfave/negroni@v1.0.0/negroni.go:46\ngithub.com/urfave/negroni.HandlerFunc.ServeHTTP\n\t/go/pkg/mod/github.com/urfave/negroni@v1.0.0/negroni.go:29\ngithub.com/urfave/negroni.middleware.ServeHTTP\n\t/go/pkg/mod/github.com/urfave/negroni@v1.0.0/negroni.go:38\ngithub.com/ory/kratos/cmd/daemon.servePublic.func1\n\t/project/cmd/daemon/serve.go:83\ngithub.com/urfave/negroni.HandlerFunc.ServeHTTP\n\t/go/pkg/mod/github.com/urfave/negroni@v1.0.0/negroni.go:29\ngithub.com/urfave/negroni.middleware.ServeHTTP\n\t/go/pkg/mod/github.com/urfave/negroni@v1.0.0/negroni.go:38\ngithub.com/ory/x/metricsx.(*Service).ServeHTTP\n\t/project/oryx/metricsx/middleware.go:281", "status": "Bad Request", "status_code": 400 }, }Relevant configuration
Version
v26.2.0
On which operating system are you observing this issue?
Linux
In which environment are you deploying?
Kubernetes with Helm
Additional Context
This is a regression. No Kratos or provider config was changed on our side.
Telegram added the ES256K key to support TON blockchain wallet authentication,
which is unrelated to standard OIDC flows.
The fix likely belongs in go-jose (graceful skip of unknown curve keys) or in
Kratos as a pre-filter step before passing the JWK set to go-jose. Worth checking
whether upgrading to new version of go-jose already resolves this behavior.
Affected JWKS entry:
{"alg":"ES256K","kty":"EC","crv":"secp256k1","kid":"oidc-es256k-1","use":"sig"}