Просмотр исходного кода

fix(oauth2): verify OIDC ID token signature before trusting claims

The ID token from the token exchange was not being validated. Now the
provider's JWKS keys are used to verify the JWT signature, issuer,
audience, and expiry. The verified subject is also cross-checked against
the UserInfo response to detect mismatches.
Frédéric Guillot 3 месяцев назад
Родитель
Сommit
5c9edf3c1b
1 измененных файлов с 15 добавлено и 0 удалено
  1. 15 0
      internal/oauth2/oidc.go

+ 15 - 0
internal/oauth2/oidc.go

@@ -60,11 +60,26 @@ func (o *oidcProvider) GetProfile(ctx context.Context, code, codeVerifier string
 		return nil, fmt.Errorf(`oidc: failed to exchange token: %w`, err)
 	}
 
+	rawIDToken, ok := token.Extra("id_token").(string)
+	if !ok {
+		return nil, errors.New(`oidc: no id_token in token response`)
+	}
+
+	verifier := o.provider.Verifier(&oidc.Config{ClientID: o.clientID})
+	idToken, err := verifier.Verify(ctx, rawIDToken)
+	if err != nil {
+		return nil, fmt.Errorf(`oidc: failed to verify id token: %w`, err)
+	}
+
 	userInfo, err := o.provider.UserInfo(ctx, oauth2.StaticTokenSource(token))
 	if err != nil {
 		return nil, fmt.Errorf(`oidc: failed to get user info: %w`, err)
 	}
 
+	if idToken.Subject != userInfo.Subject {
+		return nil, fmt.Errorf(`oidc: id token subject %q does not match userinfo subject %q`, idToken.Subject, userInfo.Subject)
+	}
+
 	profile := &Profile{
 		Key: o.GetUserExtraKey(),
 		ID:  userInfo.Subject,