• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

zalando / logbook / 5242

09 Jan 2026 05:56PM UTC coverage: 98.199% (-1.8%) from 100.0%
5242

push

github

web-flow
Fix coveral on main builds (#2201)

* Switch to com.github.hazendaz.maven:coveralls-maven-plugin as org.eluder.coveralls is deprecated

* tmp allow coveral on PRs

* revert the tmp allow coveral on PRs

* use ${project.artifactId} instaed of ${artifactId} in pom.xml

754 of 768 branches covered (98.18%)

3871 of 3942 relevant lines covered (98.2%)

0.98 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/logbook-core/src/main/java/org/zalando/logbook/core/attributes/JwtClaimsExtractor.java
1
package org.zalando.logbook.core.attributes;
2

3
import java.util.Base64;
4
import java.util.Collections;
5
import java.util.HashMap;
6
import java.util.List;
7
import java.util.Map;
8
import java.util.regex.Matcher;
9
import java.util.regex.Pattern;
10
import jakarta.annotation.Nonnull;
11
import lombok.AllArgsConstructor;
12
import lombok.EqualsAndHashCode;
13
import lombok.extern.slf4j.Slf4j;
14
import org.apiguardian.api.API;
15
import org.zalando.logbook.HttpHeaders;
16
import org.zalando.logbook.HttpRequest;
17
import org.zalando.logbook.attributes.AttributeExtractor;
18
import tools.jackson.databind.json.JsonMapper;
19

20
import static org.apiguardian.api.API.Status.EXPERIMENTAL;
21

22
/**
23
 * Extracts a single claim from the JWT bearer token in the request Authorization header.
24
 * By default, the subject claim "sub" is extracted, but you can pass an (ordered) list of <code>claimNames</code>
25
 * to be scanned. The first claim in <code>claimNames</code> is then returned, or an empty attribute if no matching
26
 * claim is found.
27
 */
28
@API(status = EXPERIMENTAL)
29
@Slf4j
×
30
@AllArgsConstructor
31
@EqualsAndHashCode
32
public final class JwtClaimsExtractor implements AttributeExtractor {
33

34
    private static final String BEARER_JWT_PATTERN = "Bearer [a-z0-9-_]+\\.([a-z0-9-_]+)\\.[a-z0-9-_]+";
35
    private static final Pattern PATTERN = Pattern.compile(BEARER_JWT_PATTERN, Pattern.CASE_INSENSITIVE);
×
36

37
    @Nonnull
38
    private final JsonMapper jsonMapper;
39

40
    @Nonnull
41
    private final List<String> claimNames;
42

43
    @SuppressWarnings("unchecked")
44
    // Map keys are guaranteed to be not null
45
    public Map<String, Object> extractClaims(@Nonnull final HttpRequest request) {
46
        HttpHeaders headers = request.getHeaders();
×
47

48
        if (claimNames.isEmpty() || headers == null) return Collections.emptyMap();
×
49

50
        String authHeader = headers.getFirst("Authorization");
×
51
        if (authHeader == null) return Collections.emptyMap();
×
52

53
        Matcher matcher = PATTERN.matcher(authHeader);
×
54
        if (!matcher.matches()) return Collections.emptyMap();
×
55

56
        String payload = new String(Base64.getUrlDecoder().decode(matcher.group(1)));
×
57
        return jsonMapper.readValue(payload, HashMap.class);
×
58
    }
59

60
    @Nonnull
61
    public String toStringValue(final Object value) {
62
        try {
63
            return (value instanceof String) ? (String) value : jsonMapper.writeValueAsString(value);
×
64
        } catch (Exception e) {
×
65
            throw new RuntimeException(e);
×
66
        }
67
    }
68

69
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc