Full Code of golang-jwt/jwt for AI

main 7ceae619e739 cached
77 files
228.0 KB
74.4k tokens
250 symbols
1 requests
Download .txt
Showing preview only (245K chars total). Download the full file or copy to clipboard to get everything.
Repository: golang-jwt/jwt
Branch: main
Commit: 7ceae619e739
Files: 77
Total size: 228.0 KB

Directory structure:
gitextract_upwvedr3/

├── .github/
│   ├── CODEOWNERS
│   ├── dependabot.yml
│   ├── release.yml
│   ├── spell-check.toml
│   └── workflows/
│       ├── build.yml
│       ├── codeql-analysis.yml
│       ├── lint.yml
│       └── spell-check.yml
├── .gitignore
├── LICENSE
├── MIGRATION_GUIDE.md
├── README.md
├── SECURITY.md
├── VERSION_HISTORY.md
├── claims.go
├── cmd/
│   └── jwt/
│       ├── README.md
│       └── main.go
├── doc.go
├── ecdsa.go
├── ecdsa_test.go
├── ecdsa_utils.go
├── ed25519.go
├── ed25519_test.go
├── ed25519_utils.go
├── errors.go
├── errors_test.go
├── example_test.go
├── go.mod
├── go.sum
├── hmac.go
├── hmac_example_test.go
├── hmac_test.go
├── http_example_test.go
├── jwt_test.go
├── map_claims.go
├── map_claims_test.go
├── none.go
├── none_test.go
├── parser.go
├── parser_option.go
├── parser_test.go
├── registered_claims.go
├── request/
│   ├── doc.go
│   ├── extractor.go
│   ├── extractor_example_test.go
│   ├── extractor_test.go
│   ├── oauth2.go
│   ├── request.go
│   └── request_test.go
├── rsa.go
├── rsa_pss.go
├── rsa_pss_test.go
├── rsa_test.go
├── rsa_utils.go
├── signing_method.go
├── staticcheck.conf
├── test/
│   ├── ec256-private.pem
│   ├── ec256-public.pem
│   ├── ec384-private.pem
│   ├── ec384-public.pem
│   ├── ec512-private.pem
│   ├── ec512-public.pem
│   ├── ed25519-private.pem
│   ├── ed25519-public.pem
│   ├── examplePaddedKey-public.pem
│   ├── helpers.go
│   ├── hmacTestKey
│   ├── privateSecure.pem
│   ├── sample_key
│   └── sample_key.pub
├── token.go
├── token_option.go
├── token_test.go
├── types.go
├── types_test.go
├── validator.go
└── validator_test.go

================================================
FILE CONTENTS
================================================

================================================
FILE: .github/CODEOWNERS
================================================
*  @oxisto @mfridman


================================================
FILE: .github/dependabot.yml
================================================
# To get started with Dependabot version updates, you'll need to specify which
# package ecosystems to update and where the package manifests are located.
# Please see the documentation for all configuration options:
# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates

version: 2
updates:
  - package-ecosystem: "github-actions"
    directory: "/"
    schedule:
      interval: "monthly"


================================================
FILE: .github/release.yml
================================================
changelog:
  categories:
    - title: 🔐 Features
      labels:
        - '*'
      exclude:
        labels:
          - dependencies
    - title: 👒 Dependencies
      labels:
        - dependencies


================================================
FILE: .github/spell-check.toml
================================================
[default]
extend-ignore-re = [
    # Ignore JWT/JWE tokens
    "\\beyJ[\\dA-Za-z=_-]+(?:\\.[\\dA-Za-z=_-]{3,}){1,4}",
]

[default.extend-identifiers]
# Common registered claim abbreviations
alg = "alg"
typ = "typ"
iss = "iss"
sub = "sub"
aud = "aud"
exp = "exp"
nbf = "nbf"
iat = "iat"
jti = "jti"
cty = "cty"

# Custom exceptions (i.e. Github Usernames, proper nouns etc)
thaJeztah = "thaJeztah"

================================================
FILE: .github/workflows/build.yml
================================================
name: build

on:
  push:
    branches:
      - main
  pull_request:
    types: [opened, synchronize, reopened]

jobs:
  build:
    runs-on: ubuntu-latest
    strategy:
      fail-fast: false
      matrix:
        go: ["1.21", "1.22", "1.23", "1.24", "1.25"]
    steps:
      - name: Checkout
        uses: actions/checkout@v6
      - name: Setup Go
        uses: actions/setup-go@v6
        with:
          go-version: "${{ matrix.go }}"
          check-latest: true
      - name: Check Go code formatting
        run: |
          if [ "$(gofmt -s -l . | wc -l)" -gt 0 ]; then
            gofmt -s -l .
            echo "Please format Go code by running: go fmt ./..."
            exit 1
          fi
      - name: Install tparse
        run: |
          mkdir -p $HOME/.local/bin
          curl -L -o $HOME/.local/bin/tparse https://github.com/mfridman/tparse/releases/latest/download/tparse_linux_x86_64
          chmod +x $HOME/.local/bin/tparse
          echo "$HOME/.local/bin" >> "$GITHUB_PATH"
      - name: Build
        run: |
          go vet ./...
          go test -v -race -count=1 -json -cover ./... | tee output.json | tparse -follow -notests || true
          tparse -format markdown -file output.json -all > $GITHUB_STEP_SUMMARY
          go build ./...
  coverage:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v6
      - name: Setup Go
        uses: actions/setup-go@v6
      - name: Coverage
        run: |
          go test -v -covermode=count -coverprofile=coverage.cov ./...
      - name: Coveralls
        uses: coverallsapp/github-action@v2
        with:
          file: coverage.cov
          format: golang


================================================
FILE: .github/workflows/codeql-analysis.yml
================================================
# For most projects, this workflow file will not need changing; you simply need
# to commit it to your repository.
#
# You may wish to alter this file to override the set of languages analyzed,
# or to provide custom queries or build logic.
#
# ******** NOTE ********
# We have attempted to detect the languages in your repository. Please check
# the `language` matrix defined below to confirm you have the correct set of
# supported CodeQL languages.
#
name: "CodeQL"

on:
  push:
    branches: [main]
  pull_request:
  schedule:
    - cron: "31 10 * * 5"

jobs:
  analyze:
    name: Analyze
    runs-on: ubuntu-latest
    permissions:
      actions: read
      contents: read
      security-events: write

    strategy:
      fail-fast: false
      matrix:
        language: ["go"]
        # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ]
        # Learn more:
        # https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed

    steps:
      - name: Checkout repository
        uses: actions/checkout@v6

      # Initializes the CodeQL tools for scanning.
      - name: Initialize CodeQL
        uses: github/codeql-action/init@v4
        with:
          languages: ${{ matrix.language }}
          # If you wish to specify custom queries, you can do so here or in a config file.
          # By default, queries listed here will override any specified in a config file.
          # Prefix the list here with "+" to use these queries and those in the config file.
          # queries: ./path/to/local/query, your-org/your-repo/queries@main

      # Autobuild attempts to build any compiled languages  (C/C++, C#, or Java).
      # If this step fails, then you should remove it and run the build manually (see below)
      - name: Autobuild
        uses: github/codeql-action/autobuild@v4

      # ℹ️ Command-line programs to run using the OS shell.
      # 📚 https://git.io/JvXDl

      # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
      #    and modify them (or add more) to build your code if your project
      #    uses a compiled language

      #- run: |
      #   make bootstrap
      #   make release

      - name: Perform CodeQL Analysis
        uses: github/codeql-action/analyze@v4


================================================
FILE: .github/workflows/lint.yml
================================================
name: golangci
on:
  push:
    branches:
      - main
  pull_request:
jobs:
  golangci:
    name: lint
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v6
      - name: Setup Go
        uses: actions/setup-go@v6
        with:
          go-version: "1.25"
          check-latest: true
      - name: golangci-lint
        uses: golangci/golangci-lint-action@v9
        with:
          # Optional: version of golangci-lint to use in form of v1.2 or v1.2.3 or `latest` to use the latest version
          version: latest

          # Optional: working directory, useful for monorepos
          # working-directory: somedir

          # Optional: golangci-lint command line arguments.
          # args: --issues-exit-code=0

          # Optional: show only new issues if it's a pull request. The default value is `false`.
          # only-new-issues: true

          # Optional: if set to true then the all caching functionality will be complete disabled,
          #           takes precedence over all other caching options.
          # skip-cache: true

          # Optional: if set to true then the action don't cache or restore ~/go/pkg.
          # skip-pkg-cache: true

          # Optional: if set to true then the action don't cache or restore ~/.cache/go-build.
          # skip-build-cache: true


================================================
FILE: .github/workflows/spell-check.yml
================================================
name: spelling

permissions:
  contents: read

on:
  push:
    branches:
      - main
  pull_request:

env:
  CLICOLOR: 1

jobs:
  spelling:
    name: Spell Check with Typos
    runs-on: ubuntu-latest
    steps:
      - name: Checkout Actions Repository
        uses: actions/checkout@v6
      - name: Spell Check Repo
        uses: crate-ci/typos@65120634e79d8374d1aa2f27e54baa0c364fff5a # v1.42.1
        with:
          config: ./.github/spell-check.toml


================================================
FILE: .gitignore
================================================
.DS_Store
bin
.idea/



================================================
FILE: LICENSE
================================================
Copyright (c) 2012 Dave Grijalva
Copyright (c) 2021 golang-jwt maintainers

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.



================================================
FILE: MIGRATION_GUIDE.md
================================================
# Migration Guide (v5.0.0)

Version `v5` contains a major rework of core functionalities in the `jwt-go`
library. This includes support for several validation options as well as a
re-design of the `Claims` interface. Lastly, we reworked how errors work under
the hood, which should provide a better overall developer experience.

Starting from [v5.0.0](https://github.com/golang-jwt/jwt/releases/tag/v5.0.0),
the import path will be:

    "github.com/golang-jwt/jwt/v5"

For most users, changing the import path *should* suffice. However, since we
intentionally changed and cleaned some of the public API, existing programs
might need to be updated. The following sections describe significant changes
and corresponding updates for existing programs.

## Parsing and Validation Options

Under the hood, a new `Validator` struct takes care of validating the claims. A
long awaited feature has been the option to fine-tune the validation of tokens.
This is now possible with several `ParserOption` functions that can be appended
to most `Parse` functions, such as `ParseWithClaims`. The most important options
and changes are:
  * Added `WithLeeway` to support specifying the leeway that is allowed when
    validating time-based claims, such as `exp` or `nbf`.
  * Changed default behavior to not check the `iat` claim. Usage of this claim
    is OPTIONAL according to the JWT RFC. The claim itself is also purely
    informational according to the RFC, so a strict validation failure is not
    recommended. If you want to check for sensible values in these claims,
    please use the `WithIssuedAt` parser option.
  * Added `WithAudience`, `WithSubject` and `WithIssuer` to support checking for
    expected `aud`, `sub` and `iss`.
  * Added `WithStrictDecoding` and `WithPaddingAllowed` options to allow
    previously global settings to enable base64 strict encoding and the parsing
    of base64 strings with padding. The latter is strictly speaking against the
    standard, but unfortunately some of the major identity providers issue some
    of these incorrect tokens. Both options are disabled by default.

## Changes to the `Claims` interface

### Complete Restructuring

Previously, the claims interface was satisfied with an implementation of a
`Valid() error` function. This had several issues:
  * The different claim types (struct claims, map claims, etc.) then contained
    similar (but not 100 % identical) code of how this validation was done. This
    lead to a lot of (almost) duplicate code and was hard to maintain
  * It was not really semantically close to what a "claim" (or a set of claims)
    really is; which is a list of defined key/value pairs with a certain
    semantic meaning.

Since all the validation functionality is now extracted into the validator, all
`VerifyXXX` and `Valid` functions have been removed from the `Claims` interface.
Instead, the interface now represents a list of getters to retrieve values with
a specific meaning. This allows us to completely decouple the validation logic
with the underlying storage representation of the claim, which could be a
struct, a map or even something stored in a database.

```go
type Claims interface {
	GetExpirationTime() (*NumericDate, error)
	GetIssuedAt() (*NumericDate, error)
	GetNotBefore() (*NumericDate, error)
	GetIssuer() (string, error)
	GetSubject() (string, error)
	GetAudience() (ClaimStrings, error)
}
```

Users that previously directly called the `Valid` function on their claims,
e.g., to perform validation independently of parsing/verifying a token, can now
use the `jwt.NewValidator` function to create a `Validator` independently of the
`Parser`.

```go
var v = jwt.NewValidator(jwt.WithLeeway(5*time.Second))
v.Validate(myClaims)
```

### Supported Claim Types and Removal of `StandardClaims`

The two standard claim types supported by this library, `MapClaims` and
`RegisteredClaims` both implement the necessary functions of this interface. The
old `StandardClaims` struct, which has already been deprecated in `v4` is now
removed.

Users using custom claims, in most cases, will not experience any changes in the
behavior as long as they embedded `RegisteredClaims`. If they created a new
claim type from scratch, they now need to implemented the proper getter
functions.

### Migrating Application Specific Logic of the old `Valid`

Previously, users could override the `Valid` method in a custom claim, for
example to extend the validation with application-specific claims. However, this
was always very dangerous, since once could easily disable the standard
validation and signature checking.

In order to avoid that, while still supporting the use-case, a new
`ClaimsValidator` interface has been introduced. This interface consists of the
`Validate() error` function. If the validator sees, that a `Claims` struct
implements this interface, the errors returned to the `Validate` function will
be *appended* to the regular standard validation. It is not possible to disable
the standard validation anymore (even only by accident).

Usage examples can be found in [example_test.go](./example_test.go), to build
claims structs like the following.

```go
// MyCustomClaims includes all registered claims, plus Foo.
type MyCustomClaims struct {
	Foo string `json:"foo"`
	jwt.RegisteredClaims
}

// Validate can be used to execute additional application-specific claims
// validation.
func (m MyCustomClaims) Validate() error {
	if m.Foo != "bar" {
		return errors.New("must be foobar")
	}

	return nil
}
```

## Changes to the `Token` and `Parser` struct

The previously global functions `DecodeSegment` and `EncodeSegment` were moved
to the `Parser` and `Token` struct respectively. This will allow us in the
future to configure the behavior of these two based on options supplied on the
parser or the token (creation). This also removes two previously global
variables and moves them to parser options `WithStrictDecoding` and
`WithPaddingAllowed`.

In order to do that, we had to adjust the way signing methods work. Previously
they were given a base64 encoded signature in `Verify` and were expected to
return a base64 encoded version of the signature in `Sign`, both as a `string`.
However, this made it necessary to have `DecodeSegment` and `EncodeSegment`
global and was a less than perfect design because we were repeating
encoding/decoding steps for all signing methods. Now, `Sign` and `Verify`
operate on a decoded signature as a `[]byte`, which feels more natural for a
cryptographic operation anyway. Lastly, `Parse` and `SignedString` take care of
the final encoding/decoding part.

In addition to that, we also changed the `Signature` field on `Token` from a
`string` to `[]byte` and this is also now populated with the decoded form. This
is also more consistent, because the other parts of the JWT, mainly `Header` and
`Claims` were already stored in decoded form in `Token`. Only the signature was
stored in base64 encoded form, which was redundant with the information in the
`Raw` field, which contains the complete token as base64.

```go
type Token struct {
	Raw       string                 // Raw contains the raw token
	Method    SigningMethod          // Method is the signing method used or to be used
	Header    map[string]any         // Header is the first segment of the token in decoded form
	Claims    Claims                 // Claims is the second segment of the token in decoded form
	Signature []byte                 // Signature is the third segment of the token in decoded form
	Valid     bool                   // Valid specifies if the token is valid
}
```

Most (if not all) of these changes should not impact the normal usage of this
library. Only users directly accessing the `Signature` field as well as
developers of custom signing methods should be affected.

# Migration Guide (v4.0.0)

Starting from [v4.0.0](https://github.com/golang-jwt/jwt/releases/tag/v4.0.0),
the import path will be:

    "github.com/golang-jwt/jwt/v4"

The `/v4` version will be backwards compatible with existing `v3.x.y` tags in
this repo, as well as `github.com/dgrijalva/jwt-go`. For most users this should
be a drop-in replacement, if you're having troubles migrating, please open an
issue.

You can replace all occurrences of `github.com/dgrijalva/jwt-go` or
`github.com/golang-jwt/jwt` with `github.com/golang-jwt/jwt/v4`, either manually
or by using tools such as `sed` or `gofmt`.

And then you'd typically run:

```
go get github.com/golang-jwt/jwt/v4
go mod tidy
```

# Older releases (before v3.2.0)

The original migration guide for older releases can be found at
https://github.com/dgrijalva/jwt-go/blob/master/MIGRATION_GUIDE.md.


================================================
FILE: README.md
================================================
# jwt-go

[![build](https://github.com/golang-jwt/jwt/actions/workflows/build.yml/badge.svg)](https://github.com/golang-jwt/jwt/actions/workflows/build.yml)
[![Go
Reference](https://pkg.go.dev/badge/github.com/golang-jwt/jwt/v5.svg)](https://pkg.go.dev/github.com/golang-jwt/jwt/v5)
[![Coverage Status](https://coveralls.io/repos/github/golang-jwt/jwt/badge.svg?branch=main)](https://coveralls.io/github/golang-jwt/jwt?branch=main)

A [go](http://www.golang.org) (or 'golang' for search engine friendliness)
implementation of [JSON Web
Tokens](https://datatracker.ietf.org/doc/html/rfc7519).

Starting with [v4.0.0](https://github.com/golang-jwt/jwt/releases/tag/v4.0.0)
this project adds Go module support, but maintains backward compatibility with
older `v3.x.y` tags and upstream `github.com/dgrijalva/jwt-go`. See the
[`MIGRATION_GUIDE.md`](./MIGRATION_GUIDE.md) for more information. Version
v5.0.0 introduces major improvements to the validation of tokens, but is not
entirely backward compatible. 

> After the original author of the library suggested migrating the maintenance
> of `jwt-go`, a dedicated team of open source maintainers decided to clone the
> existing library into this repository. See
> [dgrijalva/jwt-go#462](https://github.com/dgrijalva/jwt-go/issues/462) for a
> detailed discussion on this topic.


**SECURITY NOTICE:** Some older versions of Go have a security issue in the
crypto/elliptic. The recommendation is to upgrade to at least 1.15 See issue
[dgrijalva/jwt-go#216](https://github.com/dgrijalva/jwt-go/issues/216) for more
detail.

**SECURITY NOTICE:** It's important that you [validate the `alg` presented is
what you
expect](https://auth0.com/blog/critical-vulnerabilities-in-json-web-token-libraries/).
This library attempts to make it easy to do the right thing by requiring key
types to match the expected alg, but you should take the extra step to verify it in
your usage.  See the examples provided.

### Supported Go versions

Our support of Go versions is aligned with Go's [version release
policy](https://golang.org/doc/devel/release#policy). So we will support a major
version of Go until there are two newer major releases. We no longer support
building jwt-go with unsupported Go versions, as these contain security
vulnerabilities that will not be fixed.

## What the heck is a JWT?

JWT.io has [a great introduction](https://jwt.io/introduction) to JSON Web
Tokens.

In short, it's a signed JSON object that does something useful (for example,
authentication).  It's commonly used for `Bearer` tokens in Oauth 2.  A token is
made of three parts, separated by `.`'s.  The first two parts are JSON objects,
that have been [base64url](https://datatracker.ietf.org/doc/html/rfc4648)
encoded.  The last part is the signature, encoded the same way.

The first part is called the header.  It contains the necessary information for
verifying the last part, the signature.  For example, which encryption method
was used for signing and what key was used.

The part in the middle is the interesting bit.  It's called the Claims and
contains the actual stuff you care about.  Refer to [RFC
7519](https://datatracker.ietf.org/doc/html/rfc7519) for information about
reserved keys and the proper way to add your own.

## What's in the box?

This library supports the parsing and verification as well as the generation and
signing of JWTs.  Current supported signing algorithms are HMAC SHA, RSA,
RSA-PSS, and ECDSA, though hooks are present for adding your own.

## Installation Guidelines

1. To install the jwt package, you first need to have
   [Go](https://go.dev/doc/install) installed, then you can use the command
   below to add `jwt-go` as a dependency in your Go program.

```sh
go get -u github.com/golang-jwt/jwt/v5
```

2. Import it in your code:

```go
import "github.com/golang-jwt/jwt/v5"
```

## Usage

A detailed usage guide, including how to sign and verify tokens can be found on
our [documentation website](https://golang-jwt.github.io/jwt/usage/create/).

## Examples

See [the project documentation](https://pkg.go.dev/github.com/golang-jwt/jwt/v5)
for examples of usage:

* [Simple example of parsing and validating a
  token](https://pkg.go.dev/github.com/golang-jwt/jwt/v5#example-Parse-Hmac)
* [Simple example of building and signing a
  token](https://pkg.go.dev/github.com/golang-jwt/jwt/v5#example-New-Hmac)
* [Directory of
  Examples](https://pkg.go.dev/github.com/golang-jwt/jwt/v5#pkg-examples)

## Compliance

This library was last reviewed to comply with [RFC
7519](https://datatracker.ietf.org/doc/html/rfc7519) dated May 2015 with a few
notable differences:

* In order to protect against accidental use of [Unsecured
  JWTs](https://datatracker.ietf.org/doc/html/rfc7519#section-6), tokens using
  `alg=none` will only be accepted if the constant
  `jwt.UnsafeAllowNoneSignatureType` is provided as the key.

## Project Status & Versioning

This library is considered production ready.  Feedback and feature requests are
appreciated.  The API should be considered stable.  There should be very few
backward-incompatible changes outside of major version updates (and only with
good reason).

This project uses [Semantic Versioning 2.0.0](http://semver.org).  Accepted pull
requests will land on `main`.  Periodically, versions will be tagged from
`main`.  You can find all the releases on [the project releases
page](https://github.com/golang-jwt/jwt/releases).

**BREAKING CHANGES:** A full list of breaking changes is available in
`VERSION_HISTORY.md`.  See [`MIGRATION_GUIDE.md`](./MIGRATION_GUIDE.md) for more information on updating
your code.

## Extensions

This library publishes all the necessary components for adding your own signing
methods or key functions.  Simply implement the `SigningMethod` interface and
register a factory method using `RegisterSigningMethod` or provide a
`jwt.Keyfunc`.

A common use case would be integrating with different 3rd party signature
providers, like key management services from various cloud providers or Hardware
Security Modules (HSMs) or to implement additional standards.

| Extension | Purpose                                                                                                  | Repo                                              |
| --------- | -------------------------------------------------------------------------------------------------------- | ------------------------------------------------- |
| GCP       | Integrates with multiple Google Cloud Platform signing tools (AppEngine, IAM API, Cloud KMS)             | https://github.com/someone1/gcp-jwt-go            |
| AWS       | Integrates with AWS Key Management Service, KMS                                                          | https://github.com/matelang/jwt-go-aws-kms        |
| JWKS      | Provides support for JWKS ([RFC 7517](https://datatracker.ietf.org/doc/html/rfc7517)) as a `jwt.Keyfunc` | https://github.com/MicahParks/keyfunc             |
| TPM       | Integrates with Trusted Platform Module (TPM)                                                            | https://github.com/salrashid123/golang-jwt-tpm    |

*Disclaimer*: Unless otherwise specified, these integrations are maintained by
third parties and should not be considered as a primary offer by any of the
mentioned cloud providers

## More

Go package documentation can be found [on
pkg.go.dev](https://pkg.go.dev/github.com/golang-jwt/jwt/v5). Additional
documentation can be found on [our project
page](https://golang-jwt.github.io/jwt/).

The command line utility included in this project (cmd/jwt) provides a
straightforward example of token creation and parsing as well as a useful tool
for debugging your own integration. You'll also find several implementation
examples in the documentation.

[golang-jwt](https://github.com/orgs/golang-jwt) incorporates a modified version
of the JWT logo, which is distributed under the terms of the [MIT
License](https://github.com/jsonwebtoken/jsonwebtoken.github.io/blob/master/LICENSE.txt).


================================================
FILE: SECURITY.md
================================================
# Security Policy

## Supported Versions

As of November 2024 (and until this document is updated), the latest version `v5` is supported. In critical cases, we might supply back-ported patches for `v4`.

## Reporting a Vulnerability

If you think you found a vulnerability, and even if you are not sure, please report it a [GitHub Security Advisory](https://github.com/golang-jwt/jwt/security/advisories/new). Please try be explicit, describe steps to reproduce the security issue with code example(s).

You will receive a response within a timely manner. If the issue is confirmed, we will do our best to release a patch as soon as possible given the complexity of the problem.

## Public Discussions

Please avoid publicly discussing a potential security vulnerability.

Let's take this offline and find a solution first, this limits the potential impact as much as possible.

We appreciate your help!


================================================
FILE: VERSION_HISTORY.md
================================================
# `jwt-go` Version History

The following version history is kept for historic purposes. To retrieve the current changes of each version, please refer to the change-log of the specific release versions on https://github.com/golang-jwt/jwt/releases.

## 4.0.0

* Introduces support for Go modules. The `v4` version will be backwards compatible with `v3.x.y`.

## 3.2.2

* Starting from this release, we are adopting the policy to support the most 2 recent versions of Go currently available. By the time of this release, this is Go 1.15 and 1.16 ([#28](https://github.com/golang-jwt/jwt/pull/28)).
* Fixed a potential issue that could occur when the verification of `exp`, `iat` or `nbf` was not required and contained invalid contents, i.e. non-numeric/date. Thanks for @thaJeztah for making us aware of that and @giorgos-f3 for originally reporting it to the formtech fork ([#40](https://github.com/golang-jwt/jwt/pull/40)).
* Added support for EdDSA / ED25519 ([#36](https://github.com/golang-jwt/jwt/pull/36)).
* Optimized allocations ([#33](https://github.com/golang-jwt/jwt/pull/33)).

## 3.2.1

* **Import Path Change**: See MIGRATION_GUIDE.md for tips on updating your code
	* Changed the import path from `github.com/dgrijalva/jwt-go` to `github.com/golang-jwt/jwt`
* Fixed type confusing issue between `string` and `[]string` in `VerifyAudience` ([#12](https://github.com/golang-jwt/jwt/pull/12)). This fixes CVE-2020-26160 

#### 3.2.0

* Added method `ParseUnverified` to allow users to split up the tasks of parsing and validation
* HMAC signing method returns `ErrInvalidKeyType` instead of `ErrInvalidKey` where appropriate
* Added options to `request.ParseFromRequest`, which allows for an arbitrary list of modifiers to parsing behavior. Initial set include `WithClaims` and `WithParser`. Existing usage of this function will continue to work as before.
* Deprecated `ParseFromRequestWithClaims` to simplify API in the future.

#### 3.1.0

* Improvements to `jwt` command line tool
* Added `SkipClaimsValidation` option to `Parser`
* Documentation updates

#### 3.0.0

* **Compatibility Breaking Changes**: See MIGRATION_GUIDE.md for tips on updating your code
	* Dropped support for `[]byte` keys when using RSA signing methods.  This convenience feature could contribute to security vulnerabilities involving mismatched key types with signing methods.
	* `ParseFromRequest` has been moved to `request` subpackage and usage has changed
	* The `Claims` property on `Token` is now type `Claims` instead of `map[string]interface{}`.  The default value is type `MapClaims`, which is an alias to `map[string]interface{}`.  This makes it possible to use a custom type when decoding claims.
* Other Additions and Changes
	* Added `Claims` interface type to allow users to decode the claims into a custom type
	* Added `ParseWithClaims`, which takes a third argument of type `Claims`.  Use this function instead of `Parse` if you have a custom type you'd like to decode into.
	* Dramatically improved the functionality and flexibility of `ParseFromRequest`, which is now in the `request` subpackage
	* Added `ParseFromRequestWithClaims` which is the `FromRequest` equivalent of `ParseWithClaims`
	* Added new interface type `Extractor`, which is used for extracting JWT strings from http requests.  Used with `ParseFromRequest` and `ParseFromRequestWithClaims`.
	* Added several new, more specific, validation errors to error type bitmask
	* Moved examples from README to executable example files
	* Signing method registry is now thread safe
	* Added new property to `ValidationError`, which contains the raw error returned by calls made by parse/verify (such as those returned by keyfunc or json parser)

#### 2.7.0

This will likely be the last backwards compatible release before 3.0.0, excluding essential bug fixes.

* Added new option `-show` to the `jwt` command that will just output the decoded token without verifying
* Error text for expired tokens includes how long it's been expired
* Fixed incorrect error returned from `ParseRSAPublicKeyFromPEM`
* Documentation updates

#### 2.6.0

* Exposed inner error within ValidationError
* Fixed validation errors when using UseJSONNumber flag
* Added several unit tests

#### 2.5.0

* Added support for signing method none.  You shouldn't use this.  The API tries to make this clear.
* Updated/fixed some documentation
* Added more helpful error message when trying to parse tokens that begin with `BEARER `

#### 2.4.0

* Added new type, Parser, to allow for configuration of various parsing parameters
	* You can now specify a list of valid signing methods.  Anything outside this set will be rejected.
	* You can now opt to use the `json.Number` type instead of `float64` when parsing token JSON
* Added support for [Travis CI](https://travis-ci.org/dgrijalva/jwt-go)
* Fixed some bugs with ECDSA parsing

#### 2.3.0

* Added support for ECDSA signing methods
* Added support for RSA PSS signing methods (requires go v1.4)

#### 2.2.0

* Gracefully handle a `nil` `Keyfunc` being passed to `Parse`.  Result will now be the parsed token and an error, instead of a panic.

#### 2.1.0

Backwards compatible API change that was missed in 2.0.0.

* The `SignedString` method on `Token` now takes `interface{}` instead of `[]byte`

#### 2.0.0

There were two major reasons for breaking backwards compatibility with this update.  The first was a refactor required to expand the width of the RSA and HMAC-SHA signing implementations.  There will likely be no required code changes to support this change.

The second update, while unfortunately requiring a small change in integration, is required to open up this library to other signing methods.  Not all keys used for all signing methods have a single standard on-disk representation.  Requiring `[]byte` as the type for all keys proved too limiting.  Additionally, this implementation allows for pre-parsed tokens to be reused, which might matter in an application that parses a high volume of tokens with a small set of keys.  Backwards compatibility has been maintained for passing `[]byte` to the RSA signing methods, but they will also accept `*rsa.PublicKey` and `*rsa.PrivateKey`.

It is likely the only integration change required here will be to change `func(t *jwt.Token) ([]byte, error)` to `func(t *jwt.Token) (interface{}, error)` when calling `Parse`.

* **Compatibility Breaking Changes**
	* `SigningMethodHS256` is now `*SigningMethodHMAC` instead of `type struct`
	* `SigningMethodRS256` is now `*SigningMethodRSA` instead of `type struct`
	* `KeyFunc` now returns `interface{}` instead of `[]byte`
	* `SigningMethod.Sign` now takes `interface{}` instead of `[]byte` for the key
	* `SigningMethod.Verify` now takes `interface{}` instead of `[]byte` for the key
* Renamed type `SigningMethodHS256` to `SigningMethodHMAC`.  Specific sizes are now just instances of this type.
    * Added public package global `SigningMethodHS256`
    * Added public package global `SigningMethodHS384`
    * Added public package global `SigningMethodHS512`
* Renamed type `SigningMethodRS256` to `SigningMethodRSA`.  Specific sizes are now just instances of this type.
    * Added public package global `SigningMethodRS256`
    * Added public package global `SigningMethodRS384`
    * Added public package global `SigningMethodRS512`
* Moved sample private key for HMAC tests from an inline value to a file on disk.  Value is unchanged.
* Refactored the RSA implementation to be easier to read
* Exposed helper methods `ParseRSAPrivateKeyFromPEM` and `ParseRSAPublicKeyFromPEM`

## 1.0.2

* Fixed bug in parsing public keys from certificates
* Added more tests around the parsing of keys for RS256
* Code refactoring in RS256 implementation.  No functional changes

## 1.0.1

* Fixed panic if RS256 signing method was passed an invalid key

## 1.0.0

* First versioned release
* API stabilized
* Supports creating, signing, parsing, and validating JWT tokens
* Supports RS256 and HS256 signing methods


================================================
FILE: claims.go
================================================
package jwt

// Claims represent any form of a JWT Claims Set according to
// https://datatracker.ietf.org/doc/html/rfc7519#section-4. In order to have a
// common basis for validation, it is required that an implementation is able to
// supply at least the claim names provided in
// https://datatracker.ietf.org/doc/html/rfc7519#section-4.1 namely `exp`,
// `iat`, `nbf`, `iss`, `sub` and `aud`.
type Claims interface {
	GetExpirationTime() (*NumericDate, error)
	GetIssuedAt() (*NumericDate, error)
	GetNotBefore() (*NumericDate, error)
	GetIssuer() (string, error)
	GetSubject() (string, error)
	GetAudience() (ClaimStrings, error)
}


================================================
FILE: cmd/jwt/README.md
================================================
`jwt` command-line tool
=======================

This is a simple tool to sign, verify and show JSON Web Tokens from
the command line.

The following will create and sign a token, then verify it and output the original claims:

     echo {\"foo\":\"bar\"} | ./jwt -key ../../test/sample_key -alg RS256 -sign - | ./jwt -key ../../test/sample_key.pub -alg RS256 -verify -

Key files should be in PEM format. Other formats are not supported by this tool.

To simply display a token, use:

    echo $JWT | ./jwt -show -

You can install this tool with the following command:

     go install github.com/golang-jwt/jwt/v5/cmd/jwt

================================================
FILE: cmd/jwt/main.go
================================================
// A useful example app.  You can use this to debug your tokens on the command line.
// This is also a great place to look at how you might use this library.
//
// Example usage:
// The following will create and sign a token, then verify it and output the original claims.
//
//	echo {\"foo\":\"bar\"} | bin/jwt -key test/sample_key -alg RS256 -sign - | bin/jwt -key test/sample_key.pub -verify -
package main

import (
	"encoding/json"
	"errors"
	"flag"
	"fmt"
	"io"
	"os"
	"regexp"
	"sort"
	"strings"

	"github.com/golang-jwt/jwt/v5"
)

var (
	// Options
	flagAlg     = flag.String("alg", "", algHelp())
	flagKey     = flag.String("key", "", "path to key file or '-' to read from stdin")
	flagCompact = flag.Bool("compact", false, "output compact JSON")
	flagDebug   = flag.Bool("debug", false, "print out all kinds of debug data")
	flagClaims  = make(ArgList)
	flagHead    = make(ArgList)

	// Modes - exactly one of these is required
	flagSign   = flag.String("sign", "", "path to claims file to sign, '-' to read from stdin, or '+' to use only -claim args")
	flagVerify = flag.String("verify", "", "path to JWT token file to verify or '-' to read from stdin")
	flagShow   = flag.String("show", "", "path to JWT token file to show without verification or '-' to read from stdin")
)

func main() {
	// Plug in Var flags
	flag.Var(flagClaims, "claim", "add additional claims. may be used more than once")
	flag.Var(flagHead, "header", "add additional header params. may be used more than once")

	// Usage message if you ask for -help or if you mess up inputs.
	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0])
		fmt.Fprintf(os.Stderr, "  One of the following flags is required: sign, verify or show\n")
		flag.PrintDefaults()
	}

	// Parse command line options
	flag.Parse()

	// Do the thing.  If something goes wrong, print error to stderr
	// and exit with a non-zero status code
	if err := start(); err != nil {
		fmt.Fprintf(os.Stderr, "Error: %v\n", err)
		os.Exit(1)
	}
}

// Figure out which thing to do and then do that
func start() error {
	switch {
	case *flagSign != "":
		return signToken()
	case *flagVerify != "":
		return verifyToken()
	case *flagShow != "":
		return showToken()
	default:
		flag.Usage()
		return fmt.Errorf("none of the required flags are present. What do you want me to do?")
	}
}

// Helper func:  Read input from specified file or stdin
func loadData(p string) (_ []byte, retErr error) {
	if p == "" {
		return nil, fmt.Errorf("no path specified")
	}

	var rdr io.Reader
	switch p {
	case "-":
		rdr = os.Stdin
	case "+":
		return []byte("{}"), nil
	default:
		f, err := os.Open(p)
		if err != nil {
			return nil, err
		}
		rdr = f
		defer func() {
			retErr = errors.Join(retErr, f.Close())
		}()
	}
	return io.ReadAll(rdr)
}

// Print a json object in accordance with the prophecy (or the command line options)
func printJSON(j any) error {
	var out []byte
	var err error

	if !*flagCompact {
		out, err = json.MarshalIndent(j, "", "    ")
	} else {
		out, err = json.Marshal(j)
	}

	if err == nil {
		fmt.Println(string(out))
	}

	return err
}

// Verify a token and output the claims.  This is a great example
// of how to verify and view a token.
func verifyToken() error {
	// get the token
	tokData, err := loadData(*flagVerify)
	if err != nil {
		return fmt.Errorf("couldn't read token: %w", err)
	}

	// trim possible whitespace from token
	tokData = regexp.MustCompile(`\s*$`).ReplaceAll(tokData, []byte{})
	if *flagDebug {
		fmt.Fprintf(os.Stderr, "Token len: %v bytes\n", len(tokData))
	}

	// Parse the token.  Load the key from command line option
	token, err := jwt.Parse(string(tokData), func(t *jwt.Token) (any, error) {
		if isNone() {
			return jwt.UnsafeAllowNoneSignatureType, nil
		}
		data, err := loadData(*flagKey)
		if err != nil {
			return nil, err
		}
		switch {
		case isEs():
			return jwt.ParseECPublicKeyFromPEM(data)
		case isRs():
			return jwt.ParseRSAPublicKeyFromPEM(data)
		case isEd():
			return jwt.ParseEdPublicKeyFromPEM(data)
		default:
			return data, nil
		}
	})

	// Print an error if we can't parse for some reason
	if err != nil {
		return fmt.Errorf("couldn't parse token: %w", err)
	}

	// Print some debug data
	if *flagDebug {
		fmt.Fprintf(os.Stderr, "Header:\n%v\n", token.Header)
		fmt.Fprintf(os.Stderr, "Claims:\n%v\n", token.Claims)
	}

	// Print the token details
	if err := printJSON(token.Claims); err != nil {
		return fmt.Errorf("failed to output claims: %w", err)
	}

	return nil
}

// Create, sign, and output a token.  This is a great, simple example of
// how to use this library to create and sign a token.
func signToken() error {
	// get the token data from command line arguments
	tokData, err := loadData(*flagSign)
	if err != nil {
		return fmt.Errorf("couldn't read token: %w", err)
	} else if *flagDebug {
		fmt.Fprintf(os.Stderr, "Token: %v bytes", len(tokData))
	}

	// parse the JSON of the claims
	var claims jwt.MapClaims
	if err := json.Unmarshal(tokData, &claims); err != nil {
		return fmt.Errorf("couldn't parse claims JSON: %w", err)
	}

	// add command line claims
	if len(flagClaims) > 0 {
		for k, v := range flagClaims {
			claims[k] = v
		}
	}

	// get the key
	var key any
	if isNone() {
		key = jwt.UnsafeAllowNoneSignatureType
	} else {
		key, err = loadData(*flagKey)
		if err != nil {
			return fmt.Errorf("couldn't read key: %w", err)
		}
	}

	// get the signing alg
	alg := jwt.GetSigningMethod(*flagAlg)
	if alg == nil {
		return fmt.Errorf("couldn't find signing method: %v", *flagAlg)
	}

	// create a new token
	token := jwt.NewWithClaims(alg, claims)

	// add command line headers
	if len(flagHead) > 0 {
		for k, v := range flagHead {
			token.Header[k] = v
		}
	}

	switch {
	case isEs():
		k, ok := key.([]byte)
		if !ok {
			return fmt.Errorf("couldn't convert key data to key")
		}
		key, err = jwt.ParseECPrivateKeyFromPEM(k)
		if err != nil {
			return err
		}
	case isRs():
		k, ok := key.([]byte)
		if !ok {
			return fmt.Errorf("couldn't convert key data to key")
		}
		key, err = jwt.ParseRSAPrivateKeyFromPEM(k)
		if err != nil {
			return err
		}
	case isEd():
		k, ok := key.([]byte)
		if !ok {
			return fmt.Errorf("couldn't convert key data to key")
		}
		key, err = jwt.ParseEdPrivateKeyFromPEM(k)
		if err != nil {
			return err
		}
	}

	out, err := token.SignedString(key)
	if err != nil {
		return fmt.Errorf("error signing token: %w", err)
	}
	fmt.Println(out)

	return nil
}

// showToken pretty-prints the token on the command line.
func showToken() error {
	// get the token
	tokData, err := loadData(*flagShow)
	if err != nil {
		return fmt.Errorf("couldn't read token: %w", err)
	}

	// trim possible whitespace from token
	tokData = regexp.MustCompile(`\s*$`).ReplaceAll(tokData, []byte{})
	if *flagDebug {
		fmt.Fprintf(os.Stderr, "Token len: %v bytes\n", len(tokData))
	}

	token, _, err := jwt.NewParser().ParseUnverified(string(tokData), make(jwt.MapClaims))
	if err != nil {
		return fmt.Errorf("malformed token: %w", err)
	}

	// Print the token details
	fmt.Println("Header:")
	if err := printJSON(token.Header); err != nil {
		return fmt.Errorf("failed to output header: %w", err)
	}

	fmt.Println("Claims:")
	if err := printJSON(token.Claims); err != nil {
		return fmt.Errorf("failed to output claims: %w", err)
	}

	return nil
}

func isEs() bool {
	return strings.HasPrefix(*flagAlg, "ES")
}

func isRs() bool {
	return strings.HasPrefix(*flagAlg, "RS") || strings.HasPrefix(*flagAlg, "PS")
}

func isEd() bool {
	return *flagAlg == "EdDSA"
}

func isNone() bool {
	return *flagAlg == "none"
}

func algHelp() string {
	algs := jwt.GetAlgorithms()
	sort.Strings(algs)

	var b strings.Builder
	b.WriteString("signing algorithm identifier, one of\n")
	for i, alg := range algs {
		if i > 0 {
			if i%7 == 0 {
				b.WriteString(",\n")
			} else {
				b.WriteString(", ")
			}
		}
		b.WriteString(alg)
	}
	return b.String()
}

type ArgList map[string]string

func (l ArgList) String() string {
	data, _ := json.Marshal(l)
	return string(data)
}

func (l ArgList) Set(arg string) error {
	parts := strings.SplitN(arg, "=", 2)
	if len(parts) != 2 {
		return fmt.Errorf("invalid argument '%v'.  Must use format 'key=value'. %v", arg, parts)
	}
	l[parts[0]] = parts[1]
	return nil
}


================================================
FILE: doc.go
================================================
// Package jwt is a Go implementation of JSON Web Tokens: http://self-issued.info/docs/draft-jones-json-web-token.html
//
// See README.md for more info.
package jwt


================================================
FILE: ecdsa.go
================================================
package jwt

import (
	"crypto"
	"crypto/ecdsa"
	"crypto/rand"
	"errors"
	"math/big"
)

var (
	// Sadly this is missing from crypto/ecdsa compared to crypto/rsa
	ErrECDSAVerification = errors.New("crypto/ecdsa: verification error")
)

// SigningMethodECDSA implements the ECDSA family of signing methods.
// Expects *ecdsa.PrivateKey for signing and *ecdsa.PublicKey for verification
type SigningMethodECDSA struct {
	Name      string
	Hash      crypto.Hash
	KeySize   int
	CurveBits int
}

// Specific instances for EC256 and company
var (
	SigningMethodES256 *SigningMethodECDSA
	SigningMethodES384 *SigningMethodECDSA
	SigningMethodES512 *SigningMethodECDSA
)

func init() {
	// ES256
	SigningMethodES256 = &SigningMethodECDSA{"ES256", crypto.SHA256, 32, 256}
	RegisterSigningMethod(SigningMethodES256.Alg(), func() SigningMethod {
		return SigningMethodES256
	})

	// ES384
	SigningMethodES384 = &SigningMethodECDSA{"ES384", crypto.SHA384, 48, 384}
	RegisterSigningMethod(SigningMethodES384.Alg(), func() SigningMethod {
		return SigningMethodES384
	})

	// ES512
	SigningMethodES512 = &SigningMethodECDSA{"ES512", crypto.SHA512, 66, 521}
	RegisterSigningMethod(SigningMethodES512.Alg(), func() SigningMethod {
		return SigningMethodES512
	})
}

func (m *SigningMethodECDSA) Alg() string {
	return m.Name
}

// Verify implements token verification for the SigningMethod.
// For this verify method, key must be an ecdsa.PublicKey struct
func (m *SigningMethodECDSA) Verify(signingString string, sig []byte, key any) error {
	// Get the key
	var ecdsaKey *ecdsa.PublicKey
	switch k := key.(type) {
	case *ecdsa.PublicKey:
		ecdsaKey = k
	default:
		return newError("ECDSA verify expects *ecdsa.PublicKey", ErrInvalidKeyType)
	}

	if len(sig) != 2*m.KeySize {
		return ErrECDSAVerification
	}

	r := big.NewInt(0).SetBytes(sig[:m.KeySize])
	s := big.NewInt(0).SetBytes(sig[m.KeySize:])

	// Create hasher
	if !m.Hash.Available() {
		return ErrHashUnavailable
	}
	hasher := m.Hash.New()
	hasher.Write([]byte(signingString))

	// Verify the signature
	if verifystatus := ecdsa.Verify(ecdsaKey, hasher.Sum(nil), r, s); verifystatus {
		return nil
	}

	return ErrECDSAVerification
}

// Sign implements token signing for the SigningMethod.
// For this signing method, key must be an ecdsa.PrivateKey struct
func (m *SigningMethodECDSA) Sign(signingString string, key any) ([]byte, error) {
	// Get the key
	var ecdsaKey *ecdsa.PrivateKey
	switch k := key.(type) {
	case *ecdsa.PrivateKey:
		ecdsaKey = k
	default:
		return nil, newError("ECDSA sign expects *ecdsa.PrivateKey", ErrInvalidKeyType)
	}

	// Create the hasher
	if !m.Hash.Available() {
		return nil, ErrHashUnavailable
	}

	hasher := m.Hash.New()
	hasher.Write([]byte(signingString))

	// Sign the string and return r, s
	if r, s, err := ecdsa.Sign(rand.Reader, ecdsaKey, hasher.Sum(nil)); err == nil {
		curveBits := ecdsaKey.Curve.Params().BitSize

		if m.CurveBits != curveBits {
			return nil, ErrInvalidKey
		}

		keyBytes := curveBits / 8
		if curveBits%8 > 0 {
			keyBytes += 1
		}

		// We serialize the outputs (r and s) into big-endian byte arrays
		// padded with zeros on the left to make sure the sizes work out.
		// Output must be 2*keyBytes long.
		out := make([]byte, 2*keyBytes)
		r.FillBytes(out[0:keyBytes]) // r is assigned to the first half of output.
		s.FillBytes(out[keyBytes:])  // s is assigned to the second half of output.

		return out, nil
	} else {
		return nil, err
	}
}


================================================
FILE: ecdsa_test.go
================================================
package jwt_test

import (
	"crypto/ecdsa"
	"os"
	"reflect"
	"strings"
	"testing"

	"github.com/golang-jwt/jwt/v5"
)

var ecdsaTestData = []struct {
	name        string
	keys        map[string]string
	tokenString string
	alg         string
	claims      map[string]any
	valid       bool
}{
	{
		"Basic ES256",
		map[string]string{"private": "test/ec256-private.pem", "public": "test/ec256-public.pem"},
		"eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiJ9.eyJmb28iOiJiYXIifQ.feG39E-bn8HXAKhzDZq7yEAPWYDhZlwTn3sePJnU9VrGMmwdXAIEyoOnrjreYlVM_Z4N13eK9-TmMTWyfKJtHQ",
		"ES256",
		map[string]any{"foo": "bar"},
		true,
	},
	{
		"Basic ES384",
		map[string]string{"private": "test/ec384-private.pem", "public": "test/ec384-public.pem"},
		"eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzM4NCJ9.eyJmb28iOiJiYXIifQ.ngAfKMbJUh0WWubSIYe5GMsA-aHNKwFbJk_wq3lq23aPp8H2anb1rRILIzVR0gUf4a8WzDtrzmiikuPWyCS6CN4-PwdgTk-5nehC7JXqlaBZU05p3toM3nWCwm_LXcld",
		"ES384",
		map[string]any{"foo": "bar"},
		true,
	},
	{
		"Basic ES512",
		map[string]string{"private": "test/ec512-private.pem", "public": "test/ec512-public.pem"},
		"eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzUxMiJ9.eyJmb28iOiJiYXIifQ.AAU0TvGQOcdg2OvrwY73NHKgfk26UDekh9Prz-L_iWuTBIBqOFCWwwLsRiHB1JOddfKAls5do1W0jR_F30JpVd-6AJeTjGKA4C1A1H6gIKwRY0o_tFDIydZCl_lMBMeG5VNFAjO86-WCSKwc3hqaGkq1MugPRq_qrF9AVbuEB4JPLyL5",
		"ES512",
		map[string]any{"foo": "bar"},
		true,
	},
	{
		"basic ES256 invalid: foo => bar",
		map[string]string{"private": "test/ec256-private.pem", "public": "test/ec256-public.pem"},
		"eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJiYXIifQ.MEQCIHoSJnmGlPaVQDqacx_2XlXEhhqtWceVopjomc2PJLtdAiAUTeGPoNYxZw0z8mgOnnIcjoxRuNDVZvybRZF3wR1l8W",
		"ES256",
		map[string]any{"foo": "bar"},
		false,
	},
}

func TestECDSAVerify(t *testing.T) {
	for _, data := range ecdsaTestData {
		var err error

		key, _ := os.ReadFile(data.keys["public"])

		var ecdsaKey *ecdsa.PublicKey
		if ecdsaKey, err = jwt.ParseECPublicKeyFromPEM(key); err != nil {
			t.Errorf("Unable to parse ECDSA public key: %v", err)
		}

		parts := strings.Split(data.tokenString, ".")

		method := jwt.GetSigningMethod(data.alg)
		err = method.Verify(strings.Join(parts[0:2], "."), decodeSegment(t, parts[2]), ecdsaKey)
		if data.valid && err != nil {
			t.Errorf("[%v] Error while verifying key: %v", data.name, err)
		}
		if !data.valid && err == nil {
			t.Errorf("[%v] Invalid key passed validation", data.name)
		}
	}
}

func TestECDSASign(t *testing.T) {
	for _, data := range ecdsaTestData {
		var err error
		key, _ := os.ReadFile(data.keys["private"])

		var ecdsaKey *ecdsa.PrivateKey
		if ecdsaKey, err = jwt.ParseECPrivateKeyFromPEM(key); err != nil {
			t.Errorf("Unable to parse ECDSA private key: %v", err)
		}

		if data.valid {
			parts := strings.Split(data.tokenString, ".")
			toSign := strings.Join(parts[0:2], ".")
			method := jwt.GetSigningMethod(data.alg)
			sig, err := method.Sign(toSign, ecdsaKey)
			if err != nil {
				t.Errorf("[%v] Error signing token: %v", data.name, err)
			}

			ssig := encodeSegment(sig)
			if ssig == parts[2] {
				t.Errorf("[%v] Identical signatures\nbefore:\n%v\nafter:\n%v", data.name, parts[2], ssig)
			}

			err = method.Verify(toSign, sig, ecdsaKey.Public())
			if err != nil {
				t.Errorf("[%v] Sign produced an invalid signature: %v", data.name, err)
			}
		}
	}
}

func BenchmarkECDSAParsing(b *testing.B) {
	for _, data := range ecdsaTestData {
		key, _ := os.ReadFile(data.keys["private"])

		b.Run(data.name, func(b *testing.B) {
			b.ReportAllocs()
			b.ResetTimer()
			b.RunParallel(func(pb *testing.PB) {
				for pb.Next() {
					if _, err := jwt.ParseECPrivateKeyFromPEM(key); err != nil {
						b.Fatalf("Unable to parse ECDSA private key: %v", err)
					}
				}
			})
		})
	}
}

func BenchmarkECDSASigning(b *testing.B) {
	for _, data := range ecdsaTestData {
		key, _ := os.ReadFile(data.keys["private"])

		ecdsaKey, err := jwt.ParseECPrivateKeyFromPEM(key)
		if err != nil {
			b.Fatalf("Unable to parse ECDSA private key: %v", err)
		}

		method := jwt.GetSigningMethod(data.alg)

		b.Run(data.name, func(b *testing.B) {
			benchmarkSigning(b, method, ecdsaKey)
		})

		// Directly call method.Sign without the decoration of *Token.
		b.Run(data.name+"/sign-only", func(b *testing.B) {
			if !data.valid {
				b.Skipf("Skipping because data is not valid")
			}

			parts := strings.Split(data.tokenString, ".")
			toSign := strings.Join(parts[0:2], ".")

			b.ReportAllocs()
			b.ResetTimer()
			for i := 0; i < b.N; i++ {
				sig, err := method.Sign(toSign, ecdsaKey)
				if err != nil {
					b.Fatalf("[%v] Error signing token: %v", data.name, err)
				}
				if reflect.DeepEqual(sig, decodeSegment(b, parts[2])) {
					b.Fatalf("[%v] Identical signatures\nbefore:\n%v\nafter:\n%v", data.name, parts[2], sig)
				}
			}
		})
	}
}

func decodeSegment(t interface{ Fatalf(string, ...any) }, signature string) (sig []byte) {
	var err error
	sig, err = jwt.NewParser().DecodeSegment(signature)
	if err != nil {
		t.Fatalf("could not decode segment: %v", err)
	}

	return
}

func encodeSegment(sig []byte) string {
	return (&jwt.Token{}).EncodeSegment(sig)
}


================================================
FILE: ecdsa_utils.go
================================================
package jwt

import (
	"crypto/ecdsa"
	"crypto/x509"
	"encoding/pem"
	"errors"
)

var (
	ErrNotECPublicKey  = errors.New("key is not a valid ECDSA public key")
	ErrNotECPrivateKey = errors.New("key is not a valid ECDSA private key")
)

// ParseECPrivateKeyFromPEM parses a PEM encoded Elliptic Curve Private Key Structure
func ParseECPrivateKeyFromPEM(key []byte) (*ecdsa.PrivateKey, error) {
	var err error

	// Parse PEM block
	var block *pem.Block
	if block, _ = pem.Decode(key); block == nil {
		return nil, ErrKeyMustBePEMEncoded
	}

	// Parse the key
	var parsedKey any
	if parsedKey, err = x509.ParseECPrivateKey(block.Bytes); err != nil {
		if parsedKey, err = x509.ParsePKCS8PrivateKey(block.Bytes); err != nil {
			return nil, err
		}
	}

	var pkey *ecdsa.PrivateKey
	var ok bool
	if pkey, ok = parsedKey.(*ecdsa.PrivateKey); !ok {
		return nil, ErrNotECPrivateKey
	}

	return pkey, nil
}

// ParseECPublicKeyFromPEM parses a PEM encoded PKCS1 or PKCS8 public key
func ParseECPublicKeyFromPEM(key []byte) (*ecdsa.PublicKey, error) {
	var err error

	// Parse PEM block
	var block *pem.Block
	if block, _ = pem.Decode(key); block == nil {
		return nil, ErrKeyMustBePEMEncoded
	}

	// Parse the key
	var parsedKey any
	if parsedKey, err = x509.ParsePKIXPublicKey(block.Bytes); err != nil {
		if cert, err := x509.ParseCertificate(block.Bytes); err == nil {
			parsedKey = cert.PublicKey
		} else {
			return nil, err
		}
	}

	var pkey *ecdsa.PublicKey
	var ok bool
	if pkey, ok = parsedKey.(*ecdsa.PublicKey); !ok {
		return nil, ErrNotECPublicKey
	}

	return pkey, nil
}


================================================
FILE: ed25519.go
================================================
package jwt

import (
	"crypto"
	"crypto/ed25519"
	"crypto/rand"
	"errors"
)

var (
	ErrEd25519Verification = errors.New("ed25519: verification error")
)

// SigningMethodEd25519 implements the EdDSA family.
// Expects ed25519.PrivateKey for signing and ed25519.PublicKey for verification
type SigningMethodEd25519 struct{}

// Specific instance for EdDSA
var (
	SigningMethodEdDSA *SigningMethodEd25519
)

func init() {
	SigningMethodEdDSA = &SigningMethodEd25519{}
	RegisterSigningMethod(SigningMethodEdDSA.Alg(), func() SigningMethod {
		return SigningMethodEdDSA
	})
}

func (m *SigningMethodEd25519) Alg() string {
	return "EdDSA"
}

// Verify implements token verification for the SigningMethod.
// For this verify method, key must be an ed25519.PublicKey
func (m *SigningMethodEd25519) Verify(signingString string, sig []byte, key any) error {
	var ed25519Key ed25519.PublicKey
	var ok bool

	if ed25519Key, ok = key.(ed25519.PublicKey); !ok {
		return newError("Ed25519 verify expects ed25519.PublicKey", ErrInvalidKeyType)
	}

	if len(ed25519Key) != ed25519.PublicKeySize {
		return ErrInvalidKey
	}

	// Verify the signature
	if !ed25519.Verify(ed25519Key, []byte(signingString), sig) {
		return ErrEd25519Verification
	}

	return nil
}

// Sign implements token signing for the SigningMethod.
// For this signing method, key must be an ed25519.PrivateKey
func (m *SigningMethodEd25519) Sign(signingString string, key any) ([]byte, error) {
	var ed25519Key crypto.Signer
	var ok bool

	if ed25519Key, ok = key.(crypto.Signer); !ok {
		return nil, newError("Ed25519 sign expects crypto.Signer", ErrInvalidKeyType)
	}

	if _, ok := ed25519Key.Public().(ed25519.PublicKey); !ok {
		return nil, ErrInvalidKey
	}

	// Sign the string and return the result. ed25519 performs a two-pass hash
	// as part of its algorithm. Therefore, we need to pass a non-prehashed
	// message into the Sign function, as indicated by crypto.Hash(0)
	sig, err := ed25519Key.Sign(rand.Reader, []byte(signingString), crypto.Hash(0))
	if err != nil {
		return nil, err
	}

	return sig, nil
}


================================================
FILE: ed25519_test.go
================================================
package jwt_test

import (
	"os"
	"strings"
	"testing"

	"github.com/golang-jwt/jwt/v5"
)

var ed25519TestData = []struct {
	name        string
	keys        map[string]string
	tokenString string
	alg         string
	claims      map[string]any
	valid       bool
}{
	{
		"Basic Ed25519",
		map[string]string{"private": "test/ed25519-private.pem", "public": "test/ed25519-public.pem"},
		"eyJhbGciOiJFRDI1NTE5IiwidHlwIjoiSldUIn0.eyJmb28iOiJiYXIifQ.ESuVzZq1cECrt9Od_gLPVG-_6uRP_8Nq-ajx6CtmlDqRJZqdejro2ilkqaQgSL-siE_3JMTUW7UwAorLaTyFCw",
		"EdDSA",
		map[string]any{"foo": "bar"},
		true,
	},
	{
		"Basic Ed25519",
		map[string]string{"private": "test/ed25519-private.pem", "public": "test/ed25519-public.pem"},
		"eyJhbGciOiJFRDI1NTE5IiwidHlwIjoiSldUIn0.eyJmb28iOiJiYXoifQ.ESuVzZq1cECrt9Od_gLPVG-_6uRP_8Nq-ajx6CtmlDqRJZqdejro2ilkqaQgSL-siE_3JMTUW7UwAorLaTyFCw",
		"EdDSA",
		map[string]any{"foo": "bar"},
		false,
	},
}

func TestEd25519Verify(t *testing.T) {
	for _, data := range ed25519TestData {
		var err error

		key, _ := os.ReadFile(data.keys["public"])

		ed25519Key, err := jwt.ParseEdPublicKeyFromPEM(key)
		if err != nil {
			t.Errorf("Unable to parse Ed25519 public key: %v", err)
		}

		parts := strings.Split(data.tokenString, ".")

		method := jwt.GetSigningMethod(data.alg)

		err = method.Verify(strings.Join(parts[0:2], "."), decodeSegment(t, parts[2]), ed25519Key)
		if data.valid && err != nil {
			t.Errorf("[%v] Error while verifying key: %v", data.name, err)
		}
		if !data.valid && err == nil {
			t.Errorf("[%v] Invalid key passed validation", data.name)
		}
	}
}

func TestEd25519Sign(t *testing.T) {
	for _, data := range ed25519TestData {
		var err error
		key, _ := os.ReadFile(data.keys["private"])

		ed25519Key, err := jwt.ParseEdPrivateKeyFromPEM(key)
		if err != nil {
			t.Errorf("Unable to parse Ed25519 private key: %v", err)
		}

		parts := strings.Split(data.tokenString, ".")

		method := jwt.GetSigningMethod(data.alg)

		sig, err := method.Sign(strings.Join(parts[0:2], "."), ed25519Key)
		if err != nil {
			t.Errorf("[%v] Error signing token: %v", data.name, err)
		}

		ssig := encodeSegment(sig)
		if ssig == parts[2] && !data.valid {
			t.Errorf("[%v] Identical signatures\nbefore:\n%v\nafter:\n%v", data.name, parts[2], ssig)
		}
	}
}


================================================
FILE: ed25519_utils.go
================================================
package jwt

import (
	"crypto"
	"crypto/ed25519"
	"crypto/x509"
	"encoding/pem"
	"errors"
)

var (
	ErrNotEdPrivateKey = errors.New("key is not a valid Ed25519 private key")
	ErrNotEdPublicKey  = errors.New("key is not a valid Ed25519 public key")
)

// ParseEdPrivateKeyFromPEM parses a PEM-encoded Edwards curve private key
func ParseEdPrivateKeyFromPEM(key []byte) (crypto.PrivateKey, error) {
	var err error

	// Parse PEM block
	var block *pem.Block
	if block, _ = pem.Decode(key); block == nil {
		return nil, ErrKeyMustBePEMEncoded
	}

	// Parse the key
	var parsedKey any
	if parsedKey, err = x509.ParsePKCS8PrivateKey(block.Bytes); err != nil {
		return nil, err
	}

	var pkey ed25519.PrivateKey
	var ok bool
	if pkey, ok = parsedKey.(ed25519.PrivateKey); !ok {
		return nil, ErrNotEdPrivateKey
	}

	return pkey, nil
}

// ParseEdPublicKeyFromPEM parses a PEM-encoded Edwards curve public key
func ParseEdPublicKeyFromPEM(key []byte) (crypto.PublicKey, error) {
	var err error

	// Parse PEM block
	var block *pem.Block
	if block, _ = pem.Decode(key); block == nil {
		return nil, ErrKeyMustBePEMEncoded
	}

	// Parse the key
	var parsedKey any
	if parsedKey, err = x509.ParsePKIXPublicKey(block.Bytes); err != nil {
		return nil, err
	}

	var pkey ed25519.PublicKey
	var ok bool
	if pkey, ok = parsedKey.(ed25519.PublicKey); !ok {
		return nil, ErrNotEdPublicKey
	}

	return pkey, nil
}


================================================
FILE: errors.go
================================================
package jwt

import (
	"errors"
	"fmt"
	"strings"
)

var (
	ErrInvalidKey                = errors.New("key is invalid")
	ErrInvalidKeyType            = errors.New("key is of invalid type")
	ErrHashUnavailable           = errors.New("the requested hash function is unavailable")
	ErrTokenMalformed            = errors.New("token is malformed")
	ErrTokenUnverifiable         = errors.New("token is unverifiable")
	ErrTokenSignatureInvalid     = errors.New("token signature is invalid")
	ErrTokenRequiredClaimMissing = errors.New("token is missing required claim")
	ErrTokenInvalidAudience      = errors.New("token has invalid audience")
	ErrTokenExpired              = errors.New("token is expired")
	ErrTokenUsedBeforeIssued     = errors.New("token used before issued")
	ErrTokenInvalidIssuer        = errors.New("token has invalid issuer")
	ErrTokenInvalidSubject       = errors.New("token has invalid subject")
	ErrTokenNotValidYet          = errors.New("token is not valid yet")
	ErrTokenInvalidId            = errors.New("token has invalid id")
	ErrTokenInvalidClaims        = errors.New("token has invalid claims")
	ErrInvalidType               = errors.New("invalid type for claim")
)

// joinedError is an error type that works similar to what [errors.Join]
// produces, with the exception that it has a nice error string; mainly its
// error messages are concatenated using a comma, rather than a newline.
type joinedError struct {
	errs []error
}

func (je joinedError) Error() string {
	msg := []string{}
	for _, err := range je.errs {
		msg = append(msg, err.Error())
	}

	return strings.Join(msg, ", ")
}

// joinErrors joins together multiple errors. Useful for scenarios where
// multiple errors next to each other occur, e.g., in claims validation.
func joinErrors(errs ...error) error {
	return &joinedError{
		errs: errs,
	}
}

// Unwrap implements the multiple error unwrapping for this error type, which is
// possible in Go 1.20.
func (je joinedError) Unwrap() []error {
	return je.errs
}

// newError creates a new error message with a detailed error message. The
// message will be prefixed with the contents of the supplied error type.
// Additionally, more errors, that provide more context can be supplied which
// will be appended to the message. This makes use of Go 1.20's possibility to
// include more than one %w formatting directive in [fmt.Errorf].
//
// For example,
//
//	newError("no keyfunc was provided", ErrTokenUnverifiable)
//
// will produce the error string
//
//	"token is unverifiable: no keyfunc was provided"
func newError(message string, err error, more ...error) error {
	var format string
	var args []any
	if message != "" {
		format = "%w: %s"
		args = []any{err, message}
	} else {
		format = "%w"
		args = []any{err}
	}

	for _, e := range more {
		format += ": %w"
		args = append(args, e)
	}

	err = fmt.Errorf(format, args...)
	return err
}


================================================
FILE: errors_test.go
================================================
package jwt

import (
	"errors"
	"io"
	"testing"
)

func Test_joinErrors(t *testing.T) {
	type args struct {
		errs []error
	}
	tests := []struct {
		name        string
		args        args
		wantErrors  []error
		wantMessage string
	}{
		{
			name: "multiple errors",
			args: args{
				errs: []error{ErrTokenNotValidYet, ErrTokenExpired},
			},
			wantErrors:  []error{ErrTokenNotValidYet, ErrTokenExpired},
			wantMessage: "token is not valid yet, token is expired",
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			err := joinErrors(tt.args.errs...)
			for _, wantErr := range tt.wantErrors {
				if !errors.Is(err, wantErr) {
					t.Errorf("joinErrors() error = %v, does not contain %v", err, wantErr)
				}
			}

			if err.Error() != tt.wantMessage {
				t.Errorf("joinErrors() error.Error() = %v, wantMessage %v", err, tt.wantMessage)
			}
		})
	}
}

func Test_newError(t *testing.T) {
	type args struct {
		message string
		err     error
		more    []error
	}
	tests := []struct {
		name        string
		args        args
		wantErrors  []error
		wantMessage string
	}{
		{
			name:        "single error",
			args:        args{message: "something is wrong", err: ErrTokenMalformed},
			wantMessage: "token is malformed: something is wrong",
			wantErrors:  []error{ErrTokenMalformed},
		},
		{
			name:        "two errors",
			args:        args{message: "something is wrong", err: ErrTokenMalformed, more: []error{io.ErrUnexpectedEOF}},
			wantMessage: "token is malformed: something is wrong: unexpected EOF",
			wantErrors:  []error{ErrTokenMalformed},
		},
		{
			name:        "two errors, no detail",
			args:        args{message: "", err: ErrTokenInvalidClaims, more: []error{ErrTokenExpired}},
			wantMessage: "token has invalid claims: token is expired",
			wantErrors:  []error{ErrTokenInvalidClaims, ErrTokenExpired},
		},
		{
			name:        "two errors, no detail and join error",
			args:        args{message: "", err: ErrTokenInvalidClaims, more: []error{joinErrors(ErrTokenExpired, ErrTokenNotValidYet)}},
			wantMessage: "token has invalid claims: token is expired, token is not valid yet",
			wantErrors:  []error{ErrTokenInvalidClaims, ErrTokenExpired, ErrTokenNotValidYet},
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			err := newError(tt.args.message, tt.args.err, tt.args.more...)
			for _, wantErr := range tt.wantErrors {
				if !errors.Is(err, wantErr) {
					t.Errorf("newError() error = %v, does not contain %v", err, wantErr)
				}
			}

			if err.Error() != tt.wantMessage {
				t.Errorf("newError() error.Error() = %v, wantMessage %v", err, tt.wantMessage)
			}
		})
	}
}


================================================
FILE: example_test.go
================================================
package jwt_test

import (
	"errors"
	"fmt"
	"log"
	"time"

	"github.com/golang-jwt/jwt/v5"
)

// Example (atypical) using the RegisteredClaims type by itself to parse a token.
// The RegisteredClaims type is designed to be embedded into your custom types
// to provide standard validation features.  You can use it alone, but there's
// no way to retrieve other fields after parsing.
// See the CustomClaimsType example for intended usage.
func ExampleNewWithClaims_registeredClaims() {
	mySigningKey := []byte("AllYourBase")

	// Create the Claims
	claims := &jwt.RegisteredClaims{
		ExpiresAt: jwt.NewNumericDate(time.Unix(1516239022, 0)),
		Issuer:    "test",
	}

	token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
	ss, err := token.SignedString(mySigningKey)
	fmt.Println(ss, err)
	// Output: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJ0ZXN0IiwiZXhwIjoxNTE2MjM5MDIyfQ.0XN_1Tpp9FszFOonIBpwha0c_SfnNI22DhTnjMshPg8 <nil>
}

// Example creating a token using a custom claims type. The RegisteredClaims is embedded
// in the custom type to allow for easy encoding, parsing and validation of registered claims.
func ExampleNewWithClaims_customClaimsType() {
	mySigningKey := []byte("AllYourBase")

	type MyCustomClaims struct {
		Foo string `json:"foo"`
		jwt.RegisteredClaims
	}

	// Create claims with multiple fields populated
	claims := MyCustomClaims{
		"bar",
		jwt.RegisteredClaims{
			// A usual scenario is to set the expiration time relative to the current time
			ExpiresAt: jwt.NewNumericDate(time.Now().Add(24 * time.Hour)),
			IssuedAt:  jwt.NewNumericDate(time.Now()),
			NotBefore: jwt.NewNumericDate(time.Now()),
			Issuer:    "test",
			Subject:   "somebody",
			ID:        "1",
			Audience:  []string{"somebody_else"},
		},
	}

	fmt.Printf("foo: %v\n", claims.Foo)

	// Create claims while leaving out some of the optional fields
	claims = MyCustomClaims{
		"bar",
		jwt.RegisteredClaims{
			// Also fixed dates can be used for the NumericDate
			ExpiresAt: jwt.NewNumericDate(time.Unix(1516239022, 0)),
			Issuer:    "test",
		},
	}

	token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
	ss, err := token.SignedString(mySigningKey)
	fmt.Println(ss, err)

	// Output: foo: bar
	// eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJiYXIiLCJpc3MiOiJ0ZXN0IiwiZXhwIjoxNTE2MjM5MDIyfQ.xVuY2FZ_MRXMIEgVQ7J-TFtaucVFRXUzHm9LmV41goM <nil>
}

// Example creating a token using a custom claims type.  The RegisteredClaims is embedded
// in the custom type to allow for easy encoding, parsing and validation of standard claims.
func ExampleParseWithClaims_customClaimsType() {
	tokenString := "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJiYXIiLCJpc3MiOiJ0ZXN0IiwiYXVkIjoic2luZ2xlIn0.QAWg1vGvnqRuCFTMcPkjZljXHh8U3L_qUjszOtQbeaA"

	type MyCustomClaims struct {
		Foo string `json:"foo"`
		jwt.RegisteredClaims
	}

	token, err := jwt.ParseWithClaims(tokenString, &MyCustomClaims{}, func(token *jwt.Token) (any, error) {
		return []byte("AllYourBase"), nil
	})
	if err != nil {
		log.Fatal(err)
	} else if claims, ok := token.Claims.(*MyCustomClaims); ok {
		fmt.Println(claims.Foo, claims.Issuer)
	} else {
		log.Fatal("unknown claims type, cannot proceed")
	}

	// Output: bar test
}

// Example creating a token using a custom claims type and validation options.  The RegisteredClaims is embedded
// in the custom type to allow for easy encoding, parsing and validation of standard claims.
func ExampleParseWithClaims_validationOptions() {
	tokenString := "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJiYXIiLCJpc3MiOiJ0ZXN0IiwiYXVkIjoic2luZ2xlIn0.QAWg1vGvnqRuCFTMcPkjZljXHh8U3L_qUjszOtQbeaA"

	type MyCustomClaims struct {
		Foo string `json:"foo"`
		jwt.RegisteredClaims
	}

	token, err := jwt.ParseWithClaims(tokenString, &MyCustomClaims{}, func(token *jwt.Token) (any, error) {
		return []byte("AllYourBase"), nil
	}, jwt.WithLeeway(5*time.Second))
	if err != nil {
		log.Fatal(err)
	} else if claims, ok := token.Claims.(*MyCustomClaims); ok {
		fmt.Println(claims.Foo, claims.Issuer)
	} else {
		log.Fatal("unknown claims type, cannot proceed")
	}

	// Output: bar test
}

type MyCustomClaims struct {
	Foo string `json:"foo"`
	jwt.RegisteredClaims
}

// Ensure we implement [jwt.ClaimsValidator] at compile time so we know our custom Validate method is used.
var _ jwt.ClaimsValidator = (*MyCustomClaims)(nil)

// Validate can be used to execute additional application-specific claims
// validation.
func (m MyCustomClaims) Validate() error {
	if m.Foo != "bar" {
		return errors.New("must be foobar")
	}

	return nil
}

// Example creating a token using a custom claims type and validation options.
// The RegisteredClaims is embedded in the custom type to allow for easy
// encoding, parsing and validation of standard claims and the function
// CustomValidation is implemented.
func ExampleParseWithClaims_customValidation() {
	tokenString := "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJiYXIiLCJpc3MiOiJ0ZXN0IiwiYXVkIjoic2luZ2xlIn0.QAWg1vGvnqRuCFTMcPkjZljXHh8U3L_qUjszOtQbeaA"

	token, err := jwt.ParseWithClaims(tokenString, &MyCustomClaims{}, func(token *jwt.Token) (any, error) {
		return []byte("AllYourBase"), nil
	}, jwt.WithLeeway(5*time.Second))
	if err != nil {
		log.Fatal(err)
	} else if claims, ok := token.Claims.(*MyCustomClaims); ok {
		fmt.Println(claims.Foo, claims.Issuer)
	} else {
		log.Fatal("unknown claims type, cannot proceed")
	}

	// Output: bar test
}

// An example of parsing the error types using errors.Is.
func ExampleParse_errorChecking() {
	// Token from another example.  This token is expired
	var tokenString = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJiYXIiLCJleHAiOjE1MDAwLCJpc3MiOiJ0ZXN0In0.HE7fK0xOQwFEr4WDgRWj4teRPZ6i3GLwD5YCm6Pwu_c"

	token, err := jwt.Parse(tokenString, func(token *jwt.Token) (any, error) {
		return []byte("AllYourBase"), nil
	})

	switch {
	case token.Valid:
		fmt.Println("You look nice today")
	case errors.Is(err, jwt.ErrTokenMalformed):
		fmt.Println("That's not even a token")
	case errors.Is(err, jwt.ErrTokenSignatureInvalid):
		// Invalid signature
		fmt.Println("Invalid signature")
	case errors.Is(err, jwt.ErrTokenExpired) || errors.Is(err, jwt.ErrTokenNotValidYet):
		// Token is either expired or not active yet
		fmt.Println("Timing is everything")
	default:
		fmt.Println("Couldn't handle this token:", err)
	}

	// Output: Timing is everything
}


================================================
FILE: go.mod
================================================
module github.com/golang-jwt/jwt/v5

go 1.21


================================================
FILE: go.sum
================================================


================================================
FILE: hmac.go
================================================
package jwt

import (
	"crypto"
	"crypto/hmac"
	"errors"
)

// SigningMethodHMAC implements the HMAC-SHA family of signing methods.
// Expects key type of []byte for both signing and validation
type SigningMethodHMAC struct {
	Name string
	Hash crypto.Hash
}

// Specific instances for HS256 and company
var (
	SigningMethodHS256  *SigningMethodHMAC
	SigningMethodHS384  *SigningMethodHMAC
	SigningMethodHS512  *SigningMethodHMAC
	ErrSignatureInvalid = errors.New("signature is invalid")
)

func init() {
	// HS256
	SigningMethodHS256 = &SigningMethodHMAC{"HS256", crypto.SHA256}
	RegisterSigningMethod(SigningMethodHS256.Alg(), func() SigningMethod {
		return SigningMethodHS256
	})

	// HS384
	SigningMethodHS384 = &SigningMethodHMAC{"HS384", crypto.SHA384}
	RegisterSigningMethod(SigningMethodHS384.Alg(), func() SigningMethod {
		return SigningMethodHS384
	})

	// HS512
	SigningMethodHS512 = &SigningMethodHMAC{"HS512", crypto.SHA512}
	RegisterSigningMethod(SigningMethodHS512.Alg(), func() SigningMethod {
		return SigningMethodHS512
	})
}

func (m *SigningMethodHMAC) Alg() string {
	return m.Name
}

// Verify implements token verification for the SigningMethod. Returns nil if
// the signature is valid. Key must be []byte.
//
// Note it is not advised to provide a []byte which was converted from a 'human
// readable' string using a subset of ASCII characters. To maximize entropy, you
// should ideally be providing a []byte key which was produced from a
// cryptographically random source, e.g. crypto/rand. Additional information
// about this, and why we intentionally are not supporting string as a key can
// be found on our usage guide
// https://golang-jwt.github.io/jwt/usage/signing_methods/#signing-methods-and-key-types.
func (m *SigningMethodHMAC) Verify(signingString string, sig []byte, key any) error {
	// Verify the key is the right type
	keyBytes, ok := key.([]byte)
	if !ok {
		return newError("HMAC verify expects []byte", ErrInvalidKeyType)
	}

	// Can we use the specified hashing method?
	if !m.Hash.Available() {
		return ErrHashUnavailable
	}

	// This signing method is symmetric, so we validate the signature
	// by reproducing the signature from the signing string and key, then
	// comparing that against the provided signature.
	hasher := hmac.New(m.Hash.New, keyBytes)
	hasher.Write([]byte(signingString))
	if !hmac.Equal(sig, hasher.Sum(nil)) {
		return ErrSignatureInvalid
	}

	// No validation errors.  Signature is good.
	return nil
}

// Sign implements token signing for the SigningMethod. Key must be []byte.
//
// Note it is not advised to provide a []byte which was converted from a 'human
// readable' string using a subset of ASCII characters. To maximize entropy, you
// should ideally be providing a []byte key which was produced from a
// cryptographically random source, e.g. crypto/rand. Additional information
// about this, and why we intentionally are not supporting string as a key can
// be found on our usage guide https://golang-jwt.github.io/jwt/usage/signing_methods/.
func (m *SigningMethodHMAC) Sign(signingString string, key any) ([]byte, error) {
	if keyBytes, ok := key.([]byte); ok {
		if !m.Hash.Available() {
			return nil, ErrHashUnavailable
		}

		hasher := hmac.New(m.Hash.New, keyBytes)
		hasher.Write([]byte(signingString))

		return hasher.Sum(nil), nil
	}

	return nil, newError("HMAC sign expects []byte", ErrInvalidKeyType)
}


================================================
FILE: hmac_example_test.go
================================================
package jwt_test

import (
	"fmt"
	"log"
	"os"
	"time"

	"github.com/golang-jwt/jwt/v5"
)

// For HMAC signing method, the key can be any []byte. It is recommended to generate
// a key using crypto/rand or something equivalent. You need the same key for signing
// and validating.
var hmacSampleSecret []byte

func init() {
	// Load sample key data
	if keyData, e := os.ReadFile("test/hmacTestKey"); e == nil {
		hmacSampleSecret = keyData
	} else {
		panic(e)
	}
}

// Example creating, signing, and encoding a JWT token using the HMAC signing method
func ExampleNewWithClaims_hmac() {
	// Create a new token object, specifying signing method and the claims
	// you would like it to contain.
	token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
		"foo": "bar",
		"nbf": time.Date(2015, 10, 10, 12, 0, 0, 0, time.UTC).Unix(),
	})
	// Sign and get the complete encoded token as a string using the secret
	tokenString, err := token.SignedString(hmacSampleSecret)

	fmt.Println(tokenString, err)
	// Output: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJiYXIiLCJuYmYiOjE0NDQ0Nzg0MDB9.u1riaD1rW97opCoAuRCTy4w58Br-Zk-bh7vLiRIsrpU <nil>
}

// Example parsing and validating a token using the HMAC signing method
func ExampleParse_hmac() {
	// sample token string taken from the New example
	tokenString := "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJiYXIiLCJuYmYiOjE0NDQ0Nzg0MDB9.u1riaD1rW97opCoAuRCTy4w58Br-Zk-bh7vLiRIsrpU"

	// Parse takes the token string and a function for looking up the key. The latter is especially
	// useful if you use multiple keys for your application.  The standard is to use 'kid' in the
	// head of the token to identify which key to use, but the parsed token (head and claims) is provided
	// to the callback, providing flexibility.
	token, err := jwt.Parse(tokenString, func(token *jwt.Token) (any, error) {
		// hmacSampleSecret is a []byte containing your secret, e.g. []byte("my_secret_key")
		return hmacSampleSecret, nil
	}, jwt.WithValidMethods([]string{jwt.SigningMethodHS256.Alg()}))
	if err != nil {
		log.Fatal(err)
	}

	if claims, ok := token.Claims.(jwt.MapClaims); ok {
		fmt.Println(claims["foo"], claims["nbf"])
	} else {
		fmt.Println(err)
	}

	// Output: bar 1.4444784e+09
}


================================================
FILE: hmac_test.go
================================================
package jwt_test

import (
	"os"
	"reflect"
	"strings"
	"testing"

	"github.com/golang-jwt/jwt/v5"
)

var hmacTestData = []struct {
	name        string
	tokenString string
	alg         string
	claims      map[string]any
	valid       bool
}{
	{
		"web sample",
		"eyJ0eXAiOiJKV1QiLA0KICJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ.dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk",
		"HS256",
		map[string]any{"iss": "joe", "exp": 1300819380, "http://example.com/is_root": true},
		true,
	},
	{
		"HS384",
		"eyJhbGciOiJIUzM4NCIsInR5cCI6IkpXVCJ9.eyJleHAiOjEuMzAwODE5MzhlKzA5LCJodHRwOi8vZXhhbXBsZS5jb20vaXNfcm9vdCI6dHJ1ZSwiaXNzIjoiam9lIn0.KWZEuOD5lbBxZ34g7F-SlVLAQ_r5KApWNWlZIIMyQVz5Zs58a7XdNzj5_0EcNoOy",
		"HS384",
		map[string]any{"iss": "joe", "exp": 1300819380, "http://example.com/is_root": true},
		true,
	},
	{
		"HS512",
		"eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJleHAiOjEuMzAwODE5MzhlKzA5LCJodHRwOi8vZXhhbXBsZS5jb20vaXNfcm9vdCI6dHJ1ZSwiaXNzIjoiam9lIn0.CN7YijRX6Aw1n2jyI2Id1w90ja-DEMYiWixhYCyHnrZ1VfJRaFQz1bEbjjA5Fn4CLYaUG432dEYmSbS4Saokmw",
		"HS512",
		map[string]any{"iss": "joe", "exp": 1300819380, "http://example.com/is_root": true},
		true,
	},
	{
		"web sample: invalid",
		"eyJ0eXAiOiJKV1QiLA0KICJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ.dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXo",
		"HS256",
		map[string]any{"iss": "joe", "exp": 1300819380, "http://example.com/is_root": true},
		false,
	},
}

// Sample data from http://tools.ietf.org/html/draft-jones-json-web-signature-04#appendix-A.1
var hmacTestKey, _ = os.ReadFile("test/hmacTestKey")

func TestHMACVerify(t *testing.T) {
	for _, data := range hmacTestData {
		parts := strings.Split(data.tokenString, ".")

		method := jwt.GetSigningMethod(data.alg)
		err := method.Verify(strings.Join(parts[0:2], "."), decodeSegment(t, parts[2]), hmacTestKey)
		if data.valid && err != nil {
			t.Errorf("[%v] Error while verifying key: %v", data.name, err)
		}
		if !data.valid && err == nil {
			t.Errorf("[%v] Invalid key passed validation", data.name)
		}
	}
}

func TestHMACSign(t *testing.T) {
	for _, data := range hmacTestData {
		if !data.valid {
			continue
		}
		parts := strings.Split(data.tokenString, ".")
		method := jwt.GetSigningMethod(data.alg)
		sig, err := method.Sign(strings.Join(parts[0:2], "."), hmacTestKey)
		if err != nil {
			t.Errorf("[%v] Error signing token: %v", data.name, err)
		}
		if !reflect.DeepEqual(sig, decodeSegment(t, parts[2])) {
			t.Errorf("[%v] Incorrect signature.\nwas:\n%v\nexpecting:\n%v", data.name, sig, parts[2])
		}
	}
}

func BenchmarkHS256Signing(b *testing.B) {
	benchmarkSigning(b, jwt.SigningMethodHS256, hmacTestKey)
}

func BenchmarkHS384Signing(b *testing.B) {
	benchmarkSigning(b, jwt.SigningMethodHS384, hmacTestKey)
}

func BenchmarkHS512Signing(b *testing.B) {
	benchmarkSigning(b, jwt.SigningMethodHS512, hmacTestKey)
}


================================================
FILE: http_example_test.go
================================================
package jwt_test

// Example HTTP auth using asymmetric crypto/RSA keys
// This is based on a (now outdated) example at https://gist.github.com/cryptix/45c33ecf0ae54828e63b

import (
	"crypto/rsa"
	"fmt"
	"io"
	"log"
	"net"
	"net/http"
	"net/url"
	"os"
	"strings"
	"time"

	"github.com/golang-jwt/jwt/v5"
	"github.com/golang-jwt/jwt/v5/request"
)

// location of the files used for signing and verification
const (
	privKeyPath = "test/sample_key"     // openssl genrsa -out app.rsa keysize
	pubKeyPath  = "test/sample_key.pub" // openssl rsa -in app.rsa -pubout > app.rsa.pub
)

var (
	verifyKey  *rsa.PublicKey
	signKey    *rsa.PrivateKey
	serverPort int
)

// read the key files before starting http handlers
func init() {
	signBytes, err := os.ReadFile(privKeyPath)
	fatal(err)

	signKey, err = jwt.ParseRSAPrivateKeyFromPEM(signBytes)
	fatal(err)

	verifyBytes, err := os.ReadFile(pubKeyPath)
	fatal(err)

	verifyKey, err = jwt.ParseRSAPublicKeyFromPEM(verifyBytes)
	fatal(err)

	http.HandleFunc("/authenticate", authHandler)
	http.HandleFunc("/restricted", restrictedHandler)

	// Setup listener
	listener, err := net.ListenTCP("tcp", &net.TCPAddr{})
	fatal(err)
	serverPort = listener.Addr().(*net.TCPAddr).Port

	log.Println("Listening...")
	go func() {
		fatal(http.Serve(listener, nil))
	}()
}

func fatal(err error) {
	if err != nil {
		log.Fatal(err)
	}
}

// Define some custom types were going to use within our tokens
type CustomerInfo struct {
	Name string
	Kind string
}

type CustomClaimsExample struct {
	jwt.RegisteredClaims
	TokenType string
	CustomerInfo
}

func Example_getTokenViaHTTP() {
	// See func authHandler for an example auth handler that produces a token
	res, err := http.PostForm(fmt.Sprintf("http://localhost:%v/authenticate", serverPort), url.Values{
		"user": {"test"},
		"pass": {"known"},
	})
	fatal(err)

	if res.StatusCode != 200 {
		fmt.Println("Unexpected status code", res.StatusCode)
	}

	// Read the token out of the response body
	buf, err := io.ReadAll(res.Body)
	fatal(err)
	_ = res.Body.Close()
	tokenString := strings.TrimSpace(string(buf))

	// Parse the token
	token, err := jwt.ParseWithClaims(tokenString, &CustomClaimsExample{}, func(token *jwt.Token) (any, error) {
		// since we only use the one private key to sign the tokens,
		// we also only use its public counter part to verify
		return verifyKey, nil
	})
	fatal(err)

	claims := token.Claims.(*CustomClaimsExample)
	fmt.Println(claims.Name)

	// Output: test
}

func Example_useTokenViaHTTP() {
	// Make a sample token
	// In a real world situation, this token will have been acquired from
	// some other API call (see Example_getTokenViaHTTP)
	token, err := createToken("foo")
	fatal(err)

	// Make request.  See func restrictedHandler for example request processor
	req, err := http.NewRequest("GET", fmt.Sprintf("http://localhost:%v/restricted", serverPort), nil)
	fatal(err)
	req.Header.Set("Authorization", fmt.Sprintf("Bearer %v", token))
	res, err := http.DefaultClient.Do(req)
	fatal(err)

	// Read the response body
	buf, err := io.ReadAll(res.Body)
	fatal(err)
	_ = res.Body.Close()
	fmt.Printf("%s", buf)

	// Output: Welcome, foo
}

func createToken(user string) (string, error) {
	// create a signer for rsa 256
	t := jwt.New(jwt.GetSigningMethod("RS256"))

	// set our claims
	t.Claims = &CustomClaimsExample{
		jwt.RegisteredClaims{
			// set the expire time
			// see https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.4
			ExpiresAt: jwt.NewNumericDate(time.Now().Add(time.Minute * 1)),
		},
		"level1",
		CustomerInfo{user, "human"},
	}

	// Creat token string
	return t.SignedString(signKey)
}

// reads the form values, checks them and creates the token
func authHandler(w http.ResponseWriter, r *http.Request) {
	// make sure its post
	if r.Method != "POST" {
		w.WriteHeader(http.StatusBadRequest)
		_, _ = fmt.Fprintln(w, "No POST", r.Method)
		return
	}

	user := r.FormValue("user")
	pass := r.FormValue("pass")

	log.Printf("Authenticate: user[%s] pass[%s]\n", user, pass)

	// check values
	if user != "test" || pass != "known" {
		w.WriteHeader(http.StatusForbidden)
		_, _ = fmt.Fprintln(w, "Wrong info")
		return
	}

	tokenString, err := createToken(user)
	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		_, _ = fmt.Fprintln(w, "Sorry, error while Signing Token!")
		log.Printf("Token Signing error: %v\n", err)
		return
	}

	w.Header().Set("Content-Type", "application/jwt")
	w.WriteHeader(http.StatusOK)
	_, _ = fmt.Fprintln(w, tokenString)
}

// only accessible with a valid token
func restrictedHandler(w http.ResponseWriter, r *http.Request) {
	// Get token from request
	token, err := request.ParseFromRequest(r, request.OAuth2Extractor, func(token *jwt.Token) (any, error) {
		// since we only use the one private key to sign the tokens,
		// we also only use its public counter part to verify
		return verifyKey, nil
	}, request.WithClaims(&CustomClaimsExample{}))

	// If the token is missing or invalid, return error
	if err != nil {
		w.WriteHeader(http.StatusUnauthorized)
		_, _ = fmt.Fprintln(w, "Invalid token:", err)
		return
	}

	// Token is valid
	_, _ = fmt.Fprintln(w, "Welcome,", token.Claims.(*CustomClaimsExample).Name)
}


================================================
FILE: jwt_test.go
================================================
package jwt

import (
	"testing"
)

func TestSplitToken(t *testing.T) {
	t.Parallel()

	tests := []struct {
		name     string
		input    string
		expected []string
		isValid  bool
	}{
		{
			name:     "valid token with three parts",
			input:    "header.claims.signature",
			expected: []string{"header", "claims", "signature"},
			isValid:  true,
		},
		{
			name:     "invalid token with two parts only",
			input:    "header.claims",
			expected: nil,
			isValid:  false,
		},
		{
			name:     "invalid token with one part only",
			input:    "header",
			expected: nil,
			isValid:  false,
		},
		{
			name:     "invalid token with extra delimiter",
			input:    "header.claims.signature.extra",
			expected: nil,
			isValid:  false,
		},
		{
			name:     "invalid empty token",
			input:    "",
			expected: nil,
			isValid:  false,
		},
		{
			name:     "valid token with empty parts",
			input:    "..signature",
			expected: []string{"", "", "signature"},
			isValid:  true,
		},
		{
			// We are just splitting the token into parts, so we don't care about the actual values.
			// It is up to the caller to validate the parts.
			name:     "valid token with all parts empty",
			input:    "..",
			expected: []string{"", "", ""},
			isValid:  true,
		},
		{
			name:     "invalid token with just delimiters and extra part",
			input:    "...",
			expected: nil,
			isValid:  false,
		},
		{
			name:     "invalid token with many delimiters",
			input:    "header.claims.signature..................",
			expected: nil,
			isValid:  false,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			parts, ok := splitToken(tt.input)
			if ok != tt.isValid {
				t.Errorf("expected %t, got %t", tt.isValid, ok)
			}
			if ok {
				for i, part := range tt.expected {
					if parts[i] != part {
						t.Errorf("expected %s, got %s", part, parts[i])
					}
				}
			}
		})
	}
}


================================================
FILE: map_claims.go
================================================
package jwt

import (
	"encoding/json"
	"fmt"
)

// MapClaims is a claims type that uses the map[string]any for JSON
// decoding. This is the default claims type if you don't supply one
type MapClaims map[string]any

// GetExpirationTime implements the Claims interface.
func (m MapClaims) GetExpirationTime() (*NumericDate, error) {
	return m.parseNumericDate("exp")
}

// GetNotBefore implements the Claims interface.
func (m MapClaims) GetNotBefore() (*NumericDate, error) {
	return m.parseNumericDate("nbf")
}

// GetIssuedAt implements the Claims interface.
func (m MapClaims) GetIssuedAt() (*NumericDate, error) {
	return m.parseNumericDate("iat")
}

// GetAudience implements the Claims interface.
func (m MapClaims) GetAudience() (ClaimStrings, error) {
	return m.parseClaimsString("aud")
}

// GetIssuer implements the Claims interface.
func (m MapClaims) GetIssuer() (string, error) {
	return m.parseString("iss")
}

// GetSubject implements the Claims interface.
func (m MapClaims) GetSubject() (string, error) {
	return m.parseString("sub")
}

// parseNumericDate tries to parse a key in the map claims type as a number
// date. This will succeed, if the underlying type is either a [float64] or a
// [json.Number]. Otherwise, nil will be returned.
func (m MapClaims) parseNumericDate(key string) (*NumericDate, error) {
	v, ok := m[key]
	if !ok {
		return nil, nil
	}

	switch exp := v.(type) {
	case float64:
		if exp == 0 {
			return nil, nil
		}

		return newNumericDateFromSeconds(exp), nil
	case json.Number:
		v, _ := exp.Float64()

		return newNumericDateFromSeconds(v), nil
	}

	return nil, newError(fmt.Sprintf("%s is invalid", key), ErrInvalidType)
}

// parseClaimsString tries to parse a key in the map claims type as a
// [ClaimsStrings] type, which can either be a string or an array of string.
func (m MapClaims) parseClaimsString(key string) (ClaimStrings, error) {
	var cs []string
	switch v := m[key].(type) {
	case string:
		cs = append(cs, v)
	case []string:
		cs = v
	case []any:
		for _, a := range v {
			vs, ok := a.(string)
			if !ok {
				return nil, newError(fmt.Sprintf("%s is invalid", key), ErrInvalidType)
			}
			cs = append(cs, vs)
		}
	}

	return cs, nil
}

// parseString tries to parse a key in the map claims type as a [string] type.
// If the key does not exist, an empty string is returned. If the key has the
// wrong type, an error is returned.
func (m MapClaims) parseString(key string) (string, error) {
	var (
		ok  bool
		raw any
		iss string
	)
	raw, ok = m[key]
	if !ok {
		return "", nil
	}

	iss, ok = raw.(string)
	if !ok {
		return "", newError(fmt.Sprintf("%s is invalid", key), ErrInvalidType)
	}

	return iss, nil
}


================================================
FILE: map_claims_test.go
================================================
package jwt

import (
	"testing"
	"time"
)

func TestVerifyAud(t *testing.T) {
	var nilInterface any
	var nilListInterface []any
	var intListInterface any = []int{1, 2, 3}
	type test struct {
		Name        string
		MapClaims   MapClaims
		Expected    bool
		Comparison  []string
		MatchAllAud bool
		Required    bool
	}
	tests := []test{
		// Matching Claim in aud
		// Required = true
		{Name: "String Aud matching required", MapClaims: MapClaims{"aud": "example.com"}, Expected: true, Required: true, Comparison: []string{"example.com"}},
		{Name: "[]String Aud with match required", MapClaims: MapClaims{"aud": []string{"example.com", "example.example.com"}}, Expected: true, Required: true, Comparison: []string{"example.com"}},
		{Name: "[]String Aud with []match any required", MapClaims: MapClaims{"aud": []string{"example.com", "example.example.com"}}, Expected: true, Required: true, Comparison: []string{"example.com", "auth.example.com"}},
		{Name: "[]String Aud with []match all required", MapClaims: MapClaims{"aud": []string{"example.com", "example.example.com"}}, Expected: true, Required: true, Comparison: []string{"example.com", "example.example.com"}, MatchAllAud: true},

		// Required = false
		{Name: "String Aud with match not required", MapClaims: MapClaims{"aud": "example.com"}, Expected: true, Required: false, Comparison: []string{"example.com"}},
		{Name: "Empty String Aud with match not required", MapClaims: MapClaims{}, Expected: true, Required: false, Comparison: []string{"example.com"}},
		{Name: "Empty String Aud with match not required", MapClaims: MapClaims{"aud": ""}, Expected: true, Required: false, Comparison: []string{"example.com"}},
		{Name: "Nil String Aud with match not required", MapClaims: MapClaims{"aud": nil}, Expected: true, Required: false, Comparison: []string{"example.com"}},

		{Name: "[]String Aud with match not required", MapClaims: MapClaims{"aud": []string{"example.com", "example.example.com"}}, Expected: true, Required: false, Comparison: []string{"example.com"}},
		{Name: "Empty []String Aud with match not required", MapClaims: MapClaims{"aud": []string{}}, Expected: true, Required: false, Comparison: []string{"example.com"}},

		// Non-Matching Claim in aud
		// Required = true
		{Name: "String Aud without match required", MapClaims: MapClaims{"aud": "not.example.com"}, Expected: false, Required: true, Comparison: []string{"example.com"}},
		{Name: "Empty String Aud without match required", MapClaims: MapClaims{"aud": ""}, Expected: false, Required: true, Comparison: []string{"example.com"}},
		{Name: "[]String Aud without match required", MapClaims: MapClaims{"aud": []string{"not.example.com", "example.example.com"}}, Expected: false, Required: true, Comparison: []string{"example.com"}},
		{Name: "Empty []String Aud without match required", MapClaims: MapClaims{"aud": []string{""}}, Expected: false, Required: true, Comparison: []string{"example.com"}},
		{Name: "String Aud without match not required", MapClaims: MapClaims{"aud": "not.example.com"}, Expected: false, Required: true, Comparison: []string{"example.com"}},
		{Name: "Empty String Aud without match not required", MapClaims: MapClaims{"aud": ""}, Expected: false, Required: true, Comparison: []string{"example.com"}},
		{Name: "[]String Aud without match not required", MapClaims: MapClaims{"aud": []string{"not.example.com", "example.example.com"}}, Expected: false, Required: true, Comparison: []string{"example.com"}},

		// Required = false
		{Name: "Empty []String Aud without match required", MapClaims: MapClaims{"aud": []string{""}}, Expected: true, Required: false, Comparison: []string{"example.com"}},

		// []any
		{Name: "Empty []interface{} Aud without match required", MapClaims: MapClaims{"aud": nilListInterface}, Expected: true, Required: false, Comparison: []string{"example.com"}},
		{Name: "[]interface{} Aud with match required", MapClaims: MapClaims{"aud": []any{"a", "foo", "example.com"}}, Expected: true, Required: true, Comparison: []string{"example.com"}},
		{Name: "[]interface{} Aud with match but invalid types", MapClaims: MapClaims{"aud": []any{"a", 5, "example.com"}}, Expected: false, Required: true, Comparison: []string{"example.com"}},
		{Name: "[]interface{} Aud int with match required", MapClaims: MapClaims{"aud": intListInterface}, Expected: false, Required: true, Comparison: []string{"example.com"}},

		// any
		{Name: "Empty interface{} Aud without match not required", MapClaims: MapClaims{"aud": nilInterface}, Expected: true, Required: false, Comparison: []string{"example.com"}},
	}

	for _, test := range tests {
		t.Run(test.Name, func(t *testing.T) {
			var opts []ParserOption

			if test.Required && test.MatchAllAud {
				opts = append(opts, WithAllAudiences(test.Comparison...))
			} else if test.Required {
				opts = append(opts, WithAudience(test.Comparison...))
			}

			validator := NewValidator(opts...)
			got := validator.Validate(test.MapClaims)

			if (got == nil) != test.Expected {
				t.Errorf("Expected %v, got %v", test.Expected, (got == nil))
			}
		})
	}
}

func TestMapclaimsVerifyIssuedAtInvalidTypeString(t *testing.T) {
	mapClaims := MapClaims{
		"iat": "foo",
	}
	want := false
	got := NewValidator(WithIssuedAt()).Validate(mapClaims)
	if want != (got == nil) {
		t.Fatalf("Failed to verify claims, wanted: %v got %v", want, (got == nil))
	}
}

func TestMapclaimsVerifyNotBeforeInvalidTypeString(t *testing.T) {
	mapClaims := MapClaims{
		"nbf": "foo",
	}
	want := false
	got := NewValidator().Validate(mapClaims)
	if want != (got == nil) {
		t.Fatalf("Failed to verify claims, wanted: %v got %v", want, (got == nil))
	}
}

func TestMapclaimsVerifyExpiresAtInvalidTypeString(t *testing.T) {
	mapClaims := MapClaims{
		"exp": "foo",
	}
	want := false
	got := NewValidator().Validate(mapClaims)

	if want != (got == nil) {
		t.Fatalf("Failed to verify claims, wanted: %v got %v", want, (got == nil))
	}
}

func TestMapClaimsVerifyExpiresAtExpire(t *testing.T) {
	exp := time.Now()
	mapClaims := MapClaims{
		"exp": float64(exp.Unix()),
	}
	want := false
	got := NewValidator(WithTimeFunc(func() time.Time {
		return exp
	})).Validate(mapClaims)
	if want != (got == nil) {
		t.Fatalf("Failed to verify claims, wanted: %v got %v", want, (got == nil))
	}

	got = NewValidator(WithTimeFunc(func() time.Time {
		return exp.Add(1 * time.Second)
	})).Validate(mapClaims)
	if want != (got == nil) {
		t.Fatalf("Failed to verify claims, wanted: %v got %v", want, (got == nil))
	}

	want = true
	got = NewValidator(WithTimeFunc(func() time.Time {
		return exp.Add(-1 * time.Second)
	})).Validate(mapClaims)
	if want != (got == nil) {
		t.Fatalf("Failed to verify claims, wanted: %v got %v", want, (got == nil))
	}
}

func TestMapClaims_parseString(t *testing.T) {
	type args struct {
		key string
	}
	tests := []struct {
		name    string
		m       MapClaims
		args    args
		want    string
		wantErr bool
	}{
		{
			name: "missing key",
			m:    MapClaims{},
			args: args{
				key: "mykey",
			},
			want:    "",
			wantErr: false,
		},
		{
			name: "wrong key type",
			m:    MapClaims{"mykey": 4},
			args: args{
				key: "mykey",
			},
			want:    "",
			wantErr: true,
		},
		{
			name: "correct key type",
			m:    MapClaims{"mykey": "mystring"},
			args: args{
				key: "mykey",
			},
			want:    "mystring",
			wantErr: false,
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			got, err := tt.m.parseString(tt.args.key)
			if (err != nil) != tt.wantErr {
				t.Errorf("MapClaims.parseString() error = %v, wantErr %v", err, tt.wantErr)
				return
			}
			if got != tt.want {
				t.Errorf("MapClaims.parseString() = %v, want %v", got, tt.want)
			}
		})
	}
}


================================================
FILE: none.go
================================================
package jwt

// SigningMethodNone implements the none signing method.  This is required by the spec
// but you probably should never use it.
var SigningMethodNone *signingMethodNone

const UnsafeAllowNoneSignatureType unsafeNoneMagicConstant = "none signing method allowed"

var NoneSignatureTypeDisallowedError error

type signingMethodNone struct{}
type unsafeNoneMagicConstant string

func init() {
	SigningMethodNone = &signingMethodNone{}
	NoneSignatureTypeDisallowedError = newError("'none' signature type is not allowed", ErrTokenUnverifiable)

	RegisterSigningMethod(SigningMethodNone.Alg(), func() SigningMethod {
		return SigningMethodNone
	})
}

func (m *signingMethodNone) Alg() string {
	return "none"
}

// Only allow 'none' alg type if UnsafeAllowNoneSignatureType is specified as the key
func (m *signingMethodNone) Verify(signingString string, sig []byte, key any) (err error) {
	// Key must be UnsafeAllowNoneSignatureType to prevent accidentally
	// accepting 'none' signing method
	if _, ok := key.(unsafeNoneMagicConstant); !ok {
		return NoneSignatureTypeDisallowedError
	}
	// If signing method is none, signature must be an empty string
	if len(sig) != 0 {
		return newError("'none' signing method with non-empty signature", ErrTokenUnverifiable)
	}

	// Accept 'none' signing method.
	return nil
}

// Only allow 'none' signing if UnsafeAllowNoneSignatureType is specified as the key
func (m *signingMethodNone) Sign(signingString string, key any) ([]byte, error) {
	if _, ok := key.(unsafeNoneMagicConstant); ok {
		return []byte{}, nil
	}

	return nil, NoneSignatureTypeDisallowedError
}


================================================
FILE: none_test.go
================================================
package jwt_test

import (
	"reflect"
	"strings"
	"testing"

	"github.com/golang-jwt/jwt/v5"
)

var noneTestData = []struct {
	name        string
	tokenString string
	alg         string
	key         any
	claims      map[string]any
	valid       bool
}{
	{
		"Basic",
		"eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJmb28iOiJiYXIifQ.",
		"none",
		jwt.UnsafeAllowNoneSignatureType,
		map[string]any{"foo": "bar"},
		true,
	},
	{
		"Basic - no key",
		"eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJmb28iOiJiYXIifQ.",
		"none",
		nil,
		map[string]any{"foo": "bar"},
		false,
	},
	{
		"Signed",
		"eyJhbGciOiJSUzM4NCIsInR5cCI6IkpXVCJ9.eyJmb28iOiJiYXIifQ.W-jEzRfBigtCWsinvVVuldiuilzVdU5ty0MvpLaSaqK9PlAWWlDQ1VIQ_qSKzwL5IXaZkvZFJXT3yL3n7OUVu7zCNJzdwznbC8Z-b0z2lYvcklJYi2VOFRcGbJtXUqgjk2oGsiqUMUMOLP70TTefkpsgqDxbRh9CDUfpOJgW-dU7cmgaoswe3wjUAUi6B6G2YEaiuXC0XScQYSYVKIzgKXJV8Zw-7AN_DBUI4GkTpsvQ9fVVjZM9csQiEXhYekyrKu1nu_POpQonGd8yqkIyXPECNmmqH5jH4sFiF67XhD7_JpkvLziBpI-uh86evBUadmHhb9Otqw3uV3NTaXLzJw",
		"none",
		jwt.UnsafeAllowNoneSignatureType,
		map[string]any{"foo": "bar"},
		false,
	},
}

func TestNoneVerify(t *testing.T) {
	for _, data := range noneTestData {
		parts := strings.Split(data.tokenString, ".")

		method := jwt.GetSigningMethod(data.alg)
		err := method.Verify(strings.Join(parts[0:2], "."), decodeSegment(t, parts[2]), data.key)
		if data.valid && err != nil {
			t.Errorf("[%v] Error while verifying key: %v", data.name, err)
		}
		if !data.valid && err == nil {
			t.Errorf("[%v] Invalid key passed validation", data.name)
		}
	}
}

func TestNoneSign(t *testing.T) {
	for _, data := range noneTestData {
		if !data.valid {
			continue
		}
		parts := strings.Split(data.tokenString, ".")
		method := jwt.GetSigningMethod(data.alg)
		sig, err := method.Sign(strings.Join(parts[0:2], "."), data.key)
		if err != nil {
			t.Errorf("[%v] Error signing token: %v", data.name, err)
		}
		if !reflect.DeepEqual(sig, decodeSegment(t, parts[2])) {
			t.Errorf("[%v] Incorrect signature.\nwas:\n%v\nexpecting:\n%v", data.name, sig, parts[2])
		}
	}
}


================================================
FILE: parser.go
================================================
package jwt

import (
	"bytes"
	"encoding/base64"
	"encoding/json"
	"fmt"
	"strings"
)

const tokenDelimiter = "."

type Parser struct {
	// If populated, only these methods will be considered valid.
	validMethods []string

	// Use JSON Number format in JSON decoder.
	useJSONNumber bool

	// Skip claims validation during token parsing.
	skipClaimsValidation bool

	validator *Validator

	decodeStrict bool

	decodePaddingAllowed bool
}

// NewParser creates a new Parser with the specified options
func NewParser(options ...ParserOption) *Parser {
	p := &Parser{
		validator: &Validator{},
	}

	// Loop through our parsing options and apply them
	for _, option := range options {
		option(p)
	}

	return p
}

// Parse parses, validates, verifies the signature and returns the parsed token.
// keyFunc will receive the parsed token and should return the key for validating.
func (p *Parser) Parse(tokenString string, keyFunc Keyfunc) (*Token, error) {
	return p.ParseWithClaims(tokenString, MapClaims{}, keyFunc)
}

// ParseWithClaims parses, validates, and verifies like Parse, but supplies a default object implementing the Claims
// interface. This provides default values which can be overridden and allows a caller to use their own type, rather
// than the default MapClaims implementation of Claims.
//
// Note: If you provide a custom claim implementation that embeds one of the standard claims (such as RegisteredClaims),
// make sure that a) you either embed a non-pointer version of the claims or b) if you are using a pointer, allocate the
// proper memory for it before passing in the overall claims, otherwise you might run into a panic.
func (p *Parser) ParseWithClaims(tokenString string, claims Claims, keyFunc Keyfunc) (*Token, error) {
	token, parts, err := p.ParseUnverified(tokenString, claims)
	if err != nil {
		return token, err
	}

	// Verify signing method is in the required set
	if p.validMethods != nil {
		var signingMethodValid = false
		var alg = token.Method.Alg()
		for _, m := range p.validMethods {
			if m == alg {
				signingMethodValid = true
				break
			}
		}
		if !signingMethodValid {
			// signing method is not in the listed set
			return token, newError(fmt.Sprintf("signing method %v is invalid", alg), ErrTokenSignatureInvalid)
		}
	}

	// Lookup key(s)
	if keyFunc == nil {
		// keyFunc was not provided.  short circuiting validation
		return token, newError("no keyfunc was provided", ErrTokenUnverifiable)
	}

	got, err := keyFunc(token)
	if err != nil {
		return token, newError("error while executing keyfunc", ErrTokenUnverifiable, err)
	}

	// Join together header and claims in order to verify them with the signature
	text := strings.Join(parts[0:2], ".")
	switch have := got.(type) {
	case VerificationKeySet:
		if len(have.Keys) == 0 {
			return token, newError("keyfunc returned empty verification key set", ErrTokenUnverifiable)
		}

		// Iterate through keys and verify signature, skipping the rest when a match is found.
		// Return the last error if no match is found.
		for _, key := range have.Keys {
			if err = token.Method.Verify(text, token.Signature, key); err == nil {
				break
			}
		}
	default:
		err = token.Method.Verify(text, token.Signature, have)
	}
	if err != nil {
		return token, newError("", ErrTokenSignatureInvalid, err)
	}

	// Validate Claims
	if !p.skipClaimsValidation {
		// Make sure we have at least a default validator
		if p.validator == nil {
			p.validator = NewValidator()
		}

		if err := p.validator.Validate(claims); err != nil {
			return token, newError("", ErrTokenInvalidClaims, err)
		}
	}

	// No errors so far, token is valid.
	token.Valid = true

	return token, nil
}

// ParseUnverified parses the token but does not validate the signature.
//
// WARNING: Don't use this method unless you know what you're doing.
//
// It's only ever useful in cases where you know the signature is valid (since it has already
// been or will be checked elsewhere in the stack) and you want to extract values from it.
func (p *Parser) ParseUnverified(tokenString string, claims Claims) (token *Token, parts []string, err error) {
	var ok bool
	parts, ok = splitToken(tokenString)
	if !ok {
		return nil, nil, newError("token contains an invalid number of segments", ErrTokenMalformed)
	}

	token = &Token{Raw: tokenString}

	// Parse Header
	var headerBytes []byte
	if headerBytes, err = p.DecodeSegment(parts[0]); err != nil {
		return token, parts, newError("could not base64 decode header", ErrTokenMalformed, err)
	}
	if err = json.Unmarshal(headerBytes, &token.Header); err != nil {
		return token, parts, newError("could not JSON decode header", ErrTokenMalformed, err)
	}

	// Parse Claims
	token.Claims = claims

	claimBytes, err := p.DecodeSegment(parts[1])
	if err != nil {
		return token, parts, newError("could not base64 decode claim", ErrTokenMalformed, err)
	}

	// If `useJSONNumber` is enabled then we must use *json.Decoder to decode
	// the claims. However, this comes with a performance penalty so only use
	// it if we must and, otherwise, simple use json.Unmarshal.
	if !p.useJSONNumber {
		// JSON Unmarshal. Special case for map type to avoid weird pointer behavior.
		if c, ok := token.Claims.(MapClaims); ok {
			err = json.Unmarshal(claimBytes, &c)
		} else {
			err = json.Unmarshal(claimBytes, &claims)
		}
	} else {
		dec := json.NewDecoder(bytes.NewBuffer(claimBytes))
		dec.UseNumber()
		// JSON Decode. Special case for map type to avoid weird pointer behavior.
		if c, ok := token.Claims.(MapClaims); ok {
			err = dec.Decode(&c)
		} else {
			err = dec.Decode(&claims)
		}
	}
	if err != nil {
		return token, parts, newError("could not JSON decode claim", ErrTokenMalformed, err)
	}

	// Lookup signature method
	if method, ok := token.Header["alg"].(string); ok {
		if token.Method = GetSigningMethod(method); token.Method == nil {
			return token, parts, newError("signing method (alg) is unavailable", ErrTokenUnverifiable)
		}
	} else {
		return token, parts, newError("signing method (alg) is unspecified", ErrTokenUnverifiable)
	}

	// Parse token signature
	token.Signature, err = p.DecodeSegment(parts[2])
	if err != nil {
		return token, parts, newError("could not base64 decode signature", ErrTokenMalformed, err)
	}

	return token, parts, nil
}

// splitToken splits a token string into three parts: header, claims, and signature. It will only
// return true if the token contains exactly two delimiters and three parts. In all other cases, it
// will return nil parts and false.
func splitToken(token string) ([]string, bool) {
	parts := make([]string, 3)
	header, remain, ok := strings.Cut(token, tokenDelimiter)
	if !ok {
		return nil, false
	}
	parts[0] = header
	claims, remain, ok := strings.Cut(remain, tokenDelimiter)
	if !ok {
		return nil, false
	}
	parts[1] = claims
	// One more cut to ensure the signature is the last part of the token and there are no more
	// delimiters. This avoids an issue where malicious input could contain additional delimiters
	// causing unnecessary overhead parsing tokens.
	signature, _, unexpected := strings.Cut(remain, tokenDelimiter)
	if unexpected {
		return nil, false
	}
	parts[2] = signature

	return parts, true
}

// DecodeSegment decodes a JWT specific base64url encoding. This function will
// take into account whether the [Parser] is configured with additional options,
// such as [WithStrictDecoding] or [WithPaddingAllowed].
func (p *Parser) DecodeSegment(seg string) ([]byte, error) {
	encoding := base64.RawURLEncoding

	if p.decodePaddingAllowed {
		if l := len(seg) % 4; l > 0 {
			seg += strings.Repeat("=", 4-l)
		}
		encoding = base64.URLEncoding
	}

	if p.decodeStrict {
		encoding = encoding.Strict()
	}
	return encoding.DecodeString(seg)
}

// Parse parses, validates, verifies the signature and returns the parsed token.
// keyFunc will receive the parsed token and should return the cryptographic key
// for verifying the signature. The caller is strongly encouraged to set the
// WithValidMethods option to validate the 'alg' claim in the token matches the
// expected algorithm. For more details about the importance of validating the
// 'alg' claim, see
// https://auth0.com/blog/critical-vulnerabilities-in-json-web-token-libraries/
func Parse(tokenString string, keyFunc Keyfunc, options ...ParserOption) (*Token, error) {
	return NewParser(options...).Parse(tokenString, keyFunc)
}

// ParseWithClaims is a shortcut for NewParser().ParseWithClaims().
//
// Note: If you provide a custom claim implementation that embeds one of the
// standard claims (such as RegisteredClaims), make sure that a) you either
// embed a non-pointer version of the claims or b) if you are using a pointer,
// allocate the proper memory for it before passing in the overall claims,
// otherwise you might run into a panic.
func ParseWithClaims(tokenString string, claims Claims, keyFunc Keyfunc, options ...ParserOption) (*Token, error) {
	return NewParser(options...).ParseWithClaims(tokenString, claims, keyFunc)
}


================================================
FILE: parser_option.go
================================================
package jwt

import "time"

// ParserOption is used to implement functional-style options that modify the
// behavior of the parser.
type ParserOption func(*Parser)

// WithValidMethods is an option to supply algorithm methods that the parser
// will check. Only those methods will be considered valid. It is heavily
// encouraged to use this option in order to prevent attacks such as
// https://auth0.com/blog/critical-vulnerabilities-in-json-web-token-libraries/.
func WithValidMethods(methods []string) ParserOption {
	return func(p *Parser) {
		p.validMethods = methods
	}
}

// WithJSONNumber is an option to configure the underlying JSON parser with
// UseNumber.
func WithJSONNumber() ParserOption {
	return func(p *Parser) {
		p.useJSONNumber = true
	}
}

// WithoutClaimsValidation is an option to disable claims validation. This
// option should only be used if you exactly know what you are doing.
func WithoutClaimsValidation() ParserOption {
	return func(p *Parser) {
		p.skipClaimsValidation = true
	}
}

// WithLeeway returns the ParserOption for specifying the leeway window.
func WithLeeway(leeway time.Duration) ParserOption {
	return func(p *Parser) {
		p.validator.leeway = leeway
	}
}

// WithTimeFunc returns the ParserOption for specifying the time func. The
// primary use-case for this is testing. If you are looking for a way to account
// for clock-skew, WithLeeway should be used instead.
func WithTimeFunc(f func() time.Time) ParserOption {
	return func(p *Parser) {
		p.validator.timeFunc = f
	}
}

// WithIssuedAt returns the ParserOption to enable verification
// of issued-at.
func WithIssuedAt() ParserOption {
	return func(p *Parser) {
		p.validator.verifyIat = true
	}
}

// WithExpirationRequired returns the ParserOption to make exp claim required.
// By default exp claim is optional.
func WithExpirationRequired() ParserOption {
	return func(p *Parser) {
		p.validator.requireExp = true
	}
}

// WithNotBeforeRequired returns the ParserOption to make nbf claim required.
// By default nbf claim is optional.
func WithNotBeforeRequired() ParserOption {
	return func(p *Parser) {
		p.validator.requireNbf = true
	}
}

// WithAudience configures the validator to require any of the specified
// audiences in the `aud` claim. Validation will fail if the audience is not
// listed in the token or the `aud` claim is missing.
//
// NOTE: While the `aud` claim is OPTIONAL in a JWT, the handling of it is
// application-specific. Since this validation API is helping developers in
// writing secure application, we decided to REQUIRE the existence of the claim,
// if an audience is expected.
func WithAudience(aud ...string) ParserOption {
	return func(p *Parser) {
		p.validator.expectedAud = aud
	}
}

// WithAllAudiences configures the validator to require all the specified
// audiences in the `aud` claim. Validation will fail if the specified audiences
// are not listed in the token or the `aud` claim is missing. Duplicates within
// the list are de-duplicated since internally, we use a map to look up the
// audiences.
//
// NOTE: While the `aud` claim is OPTIONAL in a JWT, the handling of it is
// application-specific. Since this validation API is helping developers in
// writing secure application, we decided to REQUIRE the existence of the claim,
// if an audience is expected.
func WithAllAudiences(aud ...string) ParserOption {
	return func(p *Parser) {
		p.validator.expectedAud = aud
		p.validator.expectAllAud = true
	}
}

// WithIssuer configures the validator to require the specified issuer in the
// `iss` claim. Validation will fail if a different issuer is specified in the
// token or the `iss` claim is missing.
//
// NOTE: While the `iss` claim is OPTIONAL in a JWT, the handling of it is
// application-specific. Since this validation API is helping developers in
// writing secure application, we decided to REQUIRE the existence of the claim,
// if an issuer is expected.
func WithIssuer(iss string) ParserOption {
	return func(p *Parser) {
		p.validator.expectedIss = iss
	}
}

// WithSubject configures the validator to require the specified subject in the
// `sub` claim. Validation will fail if a different subject is specified in the
// token or the `sub` claim is missing.
//
// NOTE: While the `sub` claim is OPTIONAL in a JWT, the handling of it is
// application-specific. Since this validation API is helping developers in
// writing secure application, we decided to REQUIRE the existence of the claim,
// if a subject is expected.
func WithSubject(sub string) ParserOption {
	return func(p *Parser) {
		p.validator.expectedSub = sub
	}
}

// WithPaddingAllowed will enable the codec used for decoding JWTs to allow
// padding. Note that the JWS RFC7515 states that the tokens will utilize a
// Base64url encoding with no padding. Unfortunately, some implementations of
// JWT are producing non-standard tokens, and thus require support for decoding.
func WithPaddingAllowed() ParserOption {
	return func(p *Parser) {
		p.decodePaddingAllowed = true
	}
}

// WithStrictDecoding will switch the codec used for decoding JWTs into strict
// mode. In this mode, the decoder requires that trailing padding bits are zero,
// as described in RFC 4648 section 3.5.
func WithStrictDecoding() ParserOption {
	return func(p *Parser) {
		p.decodeStrict = true
	}
}


================================================
FILE: parser_test.go
================================================
package jwt_test

import (
	"crypto"
	"crypto/rsa"
	"encoding/json"
	"errors"
	"fmt"
	"reflect"
	"testing"
	"time"

	"github.com/golang-jwt/jwt/v5"
	"github.com/golang-jwt/jwt/v5/test"
)

var errKeyFuncError error = fmt.Errorf("error loading key")

// customClaimsWithDifferentTypes embeds the standard jwt.RegisteredClaims
// struct, along with other valid JSON Data Types
type customClaimsWithDifferentTypes struct {
	StringClaim     string       `json:"stringClaim"`
	IntClaim        int          `json:"intClaim"`
	BoolClaim       bool         `json:"boolClaim"`
	UintClaim       uint         `json:"uintClaim"`
	FloatClaim      float64      `json:"floatClaim"`
	SliceClaim      []int        `json:"sliceClaim"`
	ObjectClaim     CustomObject `json:"objectClaim"`
	NilPointerClaim *int         `json:"nilPointerClaim"`

	jwt.RegisteredClaims
}

type CustomObject struct {
	Property string `json:"property"`
}

var (
	jwtTestDefaultKey      *rsa.PublicKey
	jwtTestRSAPrivateKey   *rsa.PrivateKey
	jwtTestEC256PublicKey  crypto.PublicKey
	jwtTestEC256PrivateKey crypto.PrivateKey
	paddedKey              crypto.PublicKey
	defaultKeyFunc         jwt.Keyfunc = func(t *jwt.Token) (any, error) { return jwtTestDefaultKey, nil }
	ecdsaKeyFunc           jwt.Keyfunc = func(t *jwt.Token) (any, error) { return jwtTestEC256PublicKey, nil }
	paddedKeyFunc          jwt.Keyfunc = func(t *jwt.Token) (any, error) { return paddedKey, nil }
	emptyKeyFunc           jwt.Keyfunc = func(t *jwt.Token) (any, error) { return nil, nil }
	errorKeyFunc           jwt.Keyfunc = func(t *jwt.Token) (any, error) { return nil, errKeyFuncError }
	nilKeyFunc             jwt.Keyfunc = nil
	multipleZeroKeyFunc    jwt.Keyfunc = func(t *jwt.Token) (any, error) { return []any{}, nil }
	multipleEmptyKeyFunc   jwt.Keyfunc = func(t *jwt.Token) (any, error) {
		return jwt.VerificationKeySet{Keys: []jwt.VerificationKey{nil, nil}}, nil
	}
	multipleVerificationKeysFunc jwt.Keyfunc = func(t *jwt.Token) (any, error) {
		return []jwt.VerificationKey{jwtTestDefaultKey, jwtTestEC256PublicKey}, nil
	}
	multipleLastKeyFunc jwt.Keyfunc = func(t *jwt.Token) (any, error) {
		return jwt.VerificationKeySet{Keys: []jwt.VerificationKey{jwtTestEC256PublicKey, jwtTestDefaultKey}}, nil
	}
	multipleFirstKeyFunc jwt.Keyfunc = func(t *jwt.Token) (any, error) {
		return jwt.VerificationKeySet{Keys: []jwt.VerificationKey{jwtTestDefaultKey, jwtTestEC256PublicKey}}, nil
	}
	multipleAltTypedKeyFunc jwt.Keyfunc = func(t *jwt.Token) (any, error) {
		return jwt.VerificationKeySet{Keys: []jwt.VerificationKey{jwtTestDefaultKey, jwtTestDefaultKey}}, nil
	}
	emptyVerificationKeySetFunc jwt.Keyfunc = func(t *jwt.Token) (any, error) {
		return jwt.VerificationKeySet{}, nil
	}
)

func init() {
	// Load public keys
	jwtTestDefaultKey = test.LoadRSAPublicKeyFromDisk("test/sample_key.pub")
	jwtTestEC256PublicKey = test.LoadECPublicKeyFromDisk("test/ec256-public.pem")

	// Load padded public key - note there is only a public key for this key pair and should only be used for the
	// two test cases below.
	paddedKey = test.LoadECPublicKeyFromDisk("test/examplePaddedKey-public.pem")

	// Load private keys
	jwtTestRSAPrivateKey = test.LoadRSAPrivateKeyFromDisk("test/sample_key")
	jwtTestEC256PrivateKey = test.LoadECPrivateKeyFromDisk("test/ec256-private.pem")
}

var jwtTestData = []struct {
	name          string
	tokenString   string
	keyfunc       jwt.Keyfunc
	claims        jwt.Claims
	valid         bool
	err           []error
	parser        *jwt.Parser
	signingMethod jwt.SigningMethod // The method to sign the JWT token for test purpose
}{
	{
		"invalid JWT",
		"thisisnotreallyajwt",
		defaultKeyFunc,
		nil,
		false,
		[]error{jwt.ErrTokenMalformed},
		nil,
		jwt.SigningMethodRS256,
	},
	{
		"invalid JSON claim",
		"eyJhbGciOiJSUzI1NiIsInppcCI6IkRFRiJ9.eNqqVkqtKFCyMjQ1s7Q0sbA0MtFRyk3NTUot8kxRslIKLbZQggn4JeamAoUcfRz99HxcXRWeze172tr4bFq7Ui0AAAD__w.jBXD4LT4aq4oXTgDoPkiV6n4QdSZPZI1Z4J8MWQC42aHK0oXwcovEU06dVbtB81TF-2byuu0-qi8J0GUttODT67k6gCl6DV_iuCOV7gczwTcvKslotUvXzoJ2wa0QuujnjxLEE50r0p6k0tsv_9OIFSUZzDksJFYNPlJH2eFG55DROx4TsOz98az37SujZi9GGbTc9SLgzFHPrHMrovRZ5qLC_w4JrdtsLzBBI11OQJgRYwV8fQf4O8IsMkHtetjkN7dKgUkJtRarNWOk76rpTPppLypiLU4_J0-wrElLMh1TzUVZW6Fz2cDHDDBACJgMmKQ2pOFEDK_vYZN74dLCF5GiTZV6DbXhNxO7lqT7JUN4a3p2z96G7WNRjblf2qZeuYdQvkIsiK-rCbSIE836XeY5gaBgkOzuEvzl_tMrpRmb5Oox1ibOfVT2KBh9Lvqsb1XbQjCio2CLE2ViCLqoe0AaRqlUyrk3n8BIG-r0IW4dcw96CEryEMIjsjVp9mtPXamJzf391kt8Rf3iRBqwv3zP7Plg1ResXbmsFUgOflAUPcYmfLug4W3W52ntcUlTHAKXrNfaJL9QQiYAaDukG-ZHDytsOWTuuXw7lVxjt-XYi1VbRAIjh1aIYSELEmEpE4Ny74htQtywYXMQNfJpB0nNn8IiWakgcYYMJ0TmKM",
		defaultKeyFunc,
		nil,
		false,
		[]error{jwt.ErrTokenMalformed},
		nil,
		jwt.SigningMethodRS256,
	},
	{
		"bearer in JWT",
		"bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJmb28iOiJiYXIifQ.FhkiHkoESI_cG3NPigFrxEk9Z60_oXrOT2vGm9Pn6RDgYNovYORQmmA0zs1AoAOf09ly2Nx2YAg6ABqAYga1AcMFkJljwxTT5fYphTuqpWdy4BELeSYJx5Ty2gmr8e7RonuUztrdD5WfPqLKMm1Ozp_T6zALpRmwTIW0QPnaBXaQD90FplAg46Iy1UlDKr-Eupy0i5SLch5Q-p2ZpaL_5fnTIUDlxC3pWhJTyx_71qDI-mAA_5lE_VdroOeflG56sSmDxopPEG3bFlSu1eowyBfxtu0_CuVd-M42RU75Zc4Gsj6uV77MBtbMrf4_7M_NUTSgoIF3fRqxrj0NzihIBg",
		defaultKeyFunc,
		nil,
		false,
		[]error{jwt.ErrTokenMalformed},
		nil,
		jwt.SigningMethodRS256,
	},
	{
		"basic",
		"eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJmb28iOiJiYXIifQ.FhkiHkoESI_cG3NPigFrxEk9Z60_oXrOT2vGm9Pn6RDgYNovYORQmmA0zs1AoAOf09ly2Nx2YAg6ABqAYga1AcMFkJljwxTT5fYphTuqpWdy4BELeSYJx5Ty2gmr8e7RonuUztrdD5WfPqLKMm1Ozp_T6zALpRmwTIW0QPnaBXaQD90FplAg46Iy1UlDKr-Eupy0i5SLch5Q-p2ZpaL_5fnTIUDlxC3pWhJTyx_71qDI-mAA_5lE_VdroOeflG56sSmDxopPEG3bFlSu1eowyBfxtu0_CuVd-M42RU75Zc4Gsj6uV77MBtbMrf4_7M_NUTSgoIF3fRqxrj0NzihIBg",
		defaultKeyFunc,
		jwt.MapClaims{"foo": "bar"},
		true,
		nil,
		nil,
		jwt.SigningMethodRS256,
	},
	/*
		custom claims with JSON Data Types
		Payload:
		{
		  "stringClaim": "string",
		  "intClaim": -1,
		  "boolClaim": true,
		  "uintClaim": 1,
		  "floatClaim": 5.01,
		  "sliceClaim": [
		    -1,
		    0,
		    1
		  ],
		  "objectClaim": {
		    "property": "something"
		  },
		  "nilPointerClaim": null
		}
	*/
	{
		"custom claims with JSON Data Types",
		"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdHJpbmdDbGFpbSI6InN0cmluZyIsImludENsYWltIjotMSwiYm9vbENsYWltIjp0cnVlLCJ1aW50Q2xhaW0iOjEsImZsb2F0Q2xhaW0iOjUuMDEsInNsaWNlQ2xhaW0iOlstMSwwLDFdLCJvYmplY3RDbGFpbSI6eyJwcm9wZXJ0eSI6InNvbWV0aGluZyJ9LCJuaWxQb2ludGVyQ2xhaW0iOm51bGx9.08Q-I2ISws_DaZnxjZ39j5EtmhGSo6dwigxMlV42kKeSVIiMDAGdukYDMJvyurrvLV19gMWkAHdLp5j23qHhP_KUcj2dKlooIFkkRvp2XuTdOtGsyCy5X7jHMYhyR4pMW7y5jor1njrxuDPBvI_oxjs-EZEYqjk8Su4_LAS5AmI2wnTR5DQAAF70WqZAvfnEwavtKSuSCYZS8ZcblBvhfufnjoXtOHbjFnIN1hEzbiLFOe-Ka_tGegYy-7RgX65ohlAFV3By48rXAcr6PLk5eG2Hz9ZSJ6GR6bozqwwnbbm7loiJYtIw7nwQSeo2sRHCw9RFG61Rq33XNlUD_kYC8Q",
		defaultKeyFunc,
		&customClaimsWithDifferentTypes{
			StringClaim: "string",
			IntClaim:    -1,
			BoolClaim:   true,
			UintClaim:   1,
			FloatClaim:  5.01,
			SliceClaim:  []int{-1, 0, 1},
			ObjectClaim: CustomObject{
				Property: "something",
			},
			NilPointerClaim: nil,
		},
		true,
		nil,
		nil,
		jwt.SigningMethodRS256,
	},
	{
		"multiple keys, last matches",
		"eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJmb28iOiJiYXIifQ.FhkiHkoESI_cG3NPigFrxEk9Z60_oXrOT2vGm9Pn6RDgYNovYORQmmA0zs1AoAOf09ly2Nx2YAg6ABqAYga1AcMFkJljwxTT5fYphTuqpWdy4BELeSYJx5Ty2gmr8e7RonuUztrdD5WfPqLKMm1Ozp_T6zALpRmwTIW0QPnaBXaQD90FplAg46Iy1UlDKr-Eupy0i5SLch5Q-p2ZpaL_5fnTIUDlxC3pWhJTyx_71qDI-mAA_5lE_VdroOeflG56sSmDxopPEG3bFlSu1eowyBfxtu0_CuVd-M42RU75Zc4Gsj6uV77MBtbMrf4_7M_NUTSgoIF3fRqxrj0NzihIBg",
		multipleLastKeyFunc,
		jwt.MapClaims{"foo": "bar"},
		true,
		nil,
		nil,
		jwt.SigningMethodRS256,
	},
	{
		"multiple keys not []interface{} type, all match",
		"eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJmb28iOiJiYXIifQ.FhkiHkoESI_cG3NPigFrxEk9Z60_oXrOT2vGm9Pn6RDgYNovYORQmmA0zs1AoAOf09ly2Nx2YAg6ABqAYga1AcMFkJljwxTT5fYphTuqpWdy4BELeSYJx5Ty2gmr8e7RonuUztrdD5WfPqLKMm1Ozp_T6zALpRmwTIW0QPnaBXaQD90FplAg46Iy1UlDKr-Eupy0i5SLch5Q-p2ZpaL_5fnTIUDlxC3pWhJTyx_71qDI-mAA_5lE_VdroOeflG56sSmDxopPEG3bFlSu1eowyBfxtu0_CuVd-M42RU75Zc4Gsj6uV77MBtbMrf4_7M_NUTSgoIF3fRqxrj0NzihIBg",
		multipleAltTypedKeyFunc,
		jwt.MapClaims{"foo": "bar"},
		true,
		nil,
		nil,
		jwt.SigningMethodRS256,
	},
	{
		"multiple keys, first matches",
		"eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJmb28iOiJiYXIifQ.FhkiHkoESI_cG3NPigFrxEk9Z60_oXrOT2vGm9Pn6RDgYNovYORQmmA0zs1AoAOf09ly2Nx2YAg6ABqAYga1AcMFkJljwxTT5fYphTuqpWdy4BELeSYJx5Ty2gmr8e7RonuUztrdD5WfPqLKMm1Ozp_T6zALpRmwTIW0QPnaBXaQD90FplAg46Iy1UlDKr-Eupy0i5SLch5Q-p2ZpaL_5fnTIUDlxC3pWhJTyx_71qDI-mAA_5lE_VdroOeflG56sSmDxopPEG3bFlSu1eowyBfxtu0_CuVd-M42RU75Zc4Gsj6uV77MBtbMrf4_7M_NUTSgoIF3fRqxrj0NzihIBg",
		multipleFirstKeyFunc,
		jwt.MapClaims{"foo": "bar"},
		true,
		nil,
		nil,
		jwt.SigningMethodRS256,
	},
	{
		"public keys slice, not allowed",
		"eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJmb28iOiJiYXIifQ.FhkiHkoESI_cG3NPigFrxEk9Z60_oXrOT2vGm9Pn6RDgYNovYORQmmA0zs1AoAOf09ly2Nx2YAg6ABqAYga1AcMFkJljwxTT5fYphTuqpWdy4BELeSYJx5Ty2gmr8e7RonuUztrdD5WfPqLKMm1Ozp_T6zALpRmwTIW0QPnaBXaQD90FplAg46Iy1UlDKr-Eupy0i5SLch5Q-p2ZpaL_5fnTIUDlxC3pWhJTyx_71qDI-mAA_5lE_VdroOeflG56sSmDxopPEG3bFlSu1eowyBfxtu0_CuVd-M42RU75Zc4Gsj6uV77MBtbMrf4_7M_NUTSgoIF3fRqxrj0NzihIBg",
		multipleVerificationKeysFunc,
		jwt.MapClaims{"foo": "bar"},
		false,
		[]error{jwt.ErrTokenSignatureInvalid},
		nil,
		jwt.SigningMethodRS256,
	},
	{
		"basic expired",
		"", // autogen
		defaultKeyFunc,
		jwt.MapClaims{"foo": "bar", "exp": float64(time.Now().Unix() - 100)},
		false,
		[]error{jwt.ErrTokenExpired},
		nil,
		jwt.SigningMethodRS256,
	},
	{
		"basic nbf",
		"", // autogen
		defaultKeyFunc,
		jwt.MapClaims{"foo": "bar", "nbf": float64(time.Now().Unix() + 100)},
		false,
		[]error{jwt.ErrTokenNotValidYet},
		nil,
		jwt.SigningMethodRS256,
	},
	{
		"expired and nbf",
		"", // autogen
		defaultKeyFunc,
		jwt.MapClaims{"foo": "bar", "nbf": float64(time.Now().Unix() + 100), "exp": float64(time.Now().Unix() - 100)},
		false,
		[]error{jwt.ErrTokenNotValidYet, jwt.ErrTokenExpired},
		nil,
		jwt.SigningMethodRS256,
	},
	{
		"basic invalid",
		"eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJmb28iOiJiYXIifQ.EhkiHkoESI_cG3NPigFrxEk9Z60_oXrOT2vGm9Pn6RDgYNovYORQmmA0zs1AoAOf09ly2Nx2YAg6ABqAYga1AcMFkJljwxTT5fYphTuqpWdy4BELeSYJx5Ty2gmr8e7RonuUztrdD5WfPqLKMm1Ozp_T6zALpRmwTIW0QPnaBXaQD90FplAg46Iy1UlDKr-Eupy0i5SLch5Q-p2ZpaL_5fnTIUDlxC3pWhJTyx_71qDI-mAA_5lE_VdroOeflG56sSmDxopPEG3bFlSu1eowyBfxtu0_CuVd-M42RU75Zc4Gsj6uV77MBtbMrf4_7M_NUTSgoIF3fRqxrj0NzihIBg",
		defaultKeyFunc,
		jwt.MapClaims{"foo": "bar"},
		false,
		[]error{jwt.ErrTokenSignatureInvalid, rsa.ErrVerification},
		nil,
		jwt.SigningMethodRS256,
	},
	{
		"basic nokeyfunc",
		"eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJmb28iOiJiYXIifQ.FhkiHkoESI_cG3NPigFrxEk9Z60_oXrOT2vGm9Pn6RDgYNovYORQmmA0zs1AoAOf09ly2Nx2YAg6ABqAYga1AcMFkJljwxTT5fYphTuqpWdy4BELeSYJx5Ty2gmr8e7RonuUztrdD5WfPqLKMm1Ozp_T6zALpRmwTIW0QPnaBXaQD90FplAg46Iy1UlDKr-Eupy0i5SLch5Q-p2ZpaL_5fnTIUDlxC3pWhJTyx_71qDI-mAA_5lE_VdroOeflG56sSmDxopPEG3bFlSu1eowyBfxtu0_CuVd-M42RU75Zc4Gsj6uV77MBtbMrf4_7M_NUTSgoIF3fRqxrj0NzihIBg",
		nilKeyFunc,
		jwt.MapClaims{"foo": "bar"},
		false,
		[]error{jwt.ErrTokenUnverifiable},
		nil,
		jwt.SigningMethodRS256,
	},
	{
		"basic nokey",
		"eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJmb28iOiJiYXIifQ.FhkiHkoESI_cG3NPigFrxEk9Z60_oXrOT2vGm9Pn6RDgYNovYORQmmA0zs1AoAOf09ly2Nx2YAg6ABqAYga1AcMFkJljwxTT5fYphTuqpWdy4BELeSYJx5Ty2gmr8e7RonuUztrdD5WfPqLKMm1Ozp_T6zALpRmwTIW0QPnaBXaQD90FplAg46Iy1UlDKr-Eupy0i5SLch5Q-p2ZpaL_5fnTIUDlxC3pWhJTyx_71qDI-mAA_5lE_VdroOeflG56sSmDxopPEG3bFlSu1eowyBfxtu0_CuVd-M42RU75Zc4Gsj6uV77MBtbMrf4_7M_NUTSgoIF3fRqxrj0NzihIBg",
		emptyKeyFunc,
		jwt.MapClaims{"foo": "bar"},
		false,
		[]error{jwt.ErrTokenSignatureInvalid},
		nil,
		jwt.SigningMethodRS256,
	},
	{
		"multiple nokey",
		"eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJmb28iOiJiYXIifQ.FhkiHkoESI_cG3NPigFrxEk9Z60_oXrOT2vGm9Pn6RDgYNovYORQmmA0zs1AoAOf09ly2Nx2YAg6ABqAYga1AcMFkJljwxTT5fYphTuqpWdy4BELeSYJx5Ty2gmr8e7RonuUztrdD5WfPqLKMm1Ozp_T6zALpRmwTIW0QPnaBXaQD90FplAg46Iy1UlDKr-Eupy0i5SLch5Q-p2ZpaL_5fnTIUDlxC3pWhJTyx_71qDI-mAA_5lE_VdroOeflG56sSmDxopPEG3bFlSu1eowyBfxtu0_CuVd-M42RU75Zc4Gsj6uV77MBtbMrf4_7M_NUTSgoIF3fRqxrj0NzihIBg",
		multipleEmptyKeyFunc,
		jwt.MapClaims{"foo": "bar"},
		false,
		[]error{jwt.ErrTokenSignatureInvalid},
		nil,
		jwt.SigningMethodRS256,
	},
	{
		"empty verification key set",
		"eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJmb28iOiJiYXIifQ.FhkiHkoESI_cG3NPigFrxEk9Z60_oXrOT2vGm9Pn6RDgYNovYORQmmA0zs1AoAOf09ly2Nx2YAg6ABqAYga1AcMFkJljwxTT5fYphTuqpWdy4BELeSYJx5Ty2gmr8e7RonuUztrdD5WfPqLKMm1Ozp_T6zALpRmwTIW0QPnaBXaQD90FplAg46Iy1UlDKr-Eupy0i5SLch5Q-p2ZpaL_5fnTIUDlxC3pWhJTyx_71qDI-mAA_5lE_VdroOeflG56sSmDxopPEG3bFlSu1eowyBfxtu0_CuVd-M42RU75Zc4Gsj6uV77MBtbMrf4_7M_NUTSgoIF3fRqxrj0NzihIBg",
		emptyVerificationKeySetFunc,
		jwt.MapClaims{"foo": "bar"},
		false,
		[]error{jwt.ErrTokenUnverifiable},
		nil,
		jwt.SigningMethodRS256,
	},
	{
		"zero length key list",
		"eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJmb28iOiJiYXIifQ.FhkiHkoESI_cG3NPigFrxEk9Z60_oXrOT2vGm9Pn6RDgYNovYORQmmA0zs1AoAOf09ly2Nx2YAg6ABqAYga1AcMFkJljwxTT5fYphTuqpWdy4BELeSYJx5Ty2gmr8e7RonuUztrdD5WfPqLKMm1Ozp_T6zALpRmwTIW0QPnaBXaQD90FplAg46Iy1UlDKr-Eupy0i5SLch5Q-p2ZpaL_5fnTIUDlxC3pWhJTyx_71qDI-mAA_5lE_VdroOeflG56sSmDxopPEG3bFlSu1eowyBfxtu0_CuVd-M42RU75Zc4Gsj6uV77MBtbMrf4_7M_NUTSgoIF3fRqxrj0NzihIBg",
		multipleZeroKeyFunc,
		jwt.MapClaims{"foo": "bar"},
		false,
		[]error{jwt.ErrTokenSignatureInvalid},
		nil,
		jwt.SigningMethodRS256,
	},
	{
		"basic errorkey",
		"eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJmb28iOiJiYXIifQ.FhkiHkoESI_cG3NPigFrxEk9Z60_oXrOT2vGm9Pn6RDgYNovYORQmmA0zs1AoAOf09ly2Nx2YAg6ABqAYga1AcMFkJljwxTT5fYphTuqpWdy4BELeSYJx5Ty2gmr8e7RonuUztrdD5WfPqLKMm1Ozp_T6zALpRmwTIW0QPnaBXaQD90FplAg46Iy1UlDKr-Eupy0i5SLch5Q-p2ZpaL_5fnTIUDlxC3pWhJTyx_71qDI-mAA_5lE_VdroOeflG56sSmDxopPEG3bFlSu1eowyBfxtu0_CuVd-M42RU75Zc4Gsj6uV77MBtbMrf4_7M_NUTSgoIF3fRqxrj0NzihIBg",
		errorKeyFunc,
		jwt.MapClaims{"foo": "bar"},
		false,
		[]error{jwt.ErrTokenUnverifiable, errKeyFuncError},
		nil,
		jwt.SigningMethodRS256,
	},
	{
		"invalid signing method",
		"",
		defaultKeyFunc,
		jwt.MapClaims{"foo": "bar"},
		false,
		[]error{jwt.ErrTokenSignatureInvalid},
		jwt.NewParser(jwt.WithValidMethods([]string{"HS256"})),
		jwt.SigningMethodRS256,
	},
	{
		"valid RSA signing method",
		"",
		defaultKeyFunc,
		jwt.MapClaims{"foo": "bar"},
		true,
		nil,
		jwt.NewParser(jwt.WithValidMethods([]string{"RS256", "HS256"})),
		jwt.SigningMethodRS256,
	},
	{
		"ECDSA signing method not accepted",
		"",
		ecdsaKeyFunc,
		jwt.MapClaims{"foo": "bar"},
		false,
		[]error{jwt.ErrTokenSignatureInvalid},
		jwt.NewParser(jwt.WithValidMethods([]string{"RS256", "HS256"})),
		jwt.SigningMethodES256,
	},
	{
		"valid ECDSA signing method",
		"",
		ecdsaKeyFunc,
		jwt.MapClaims{"foo": "bar"},
		true,
		nil,
		jwt.NewParser(jwt.WithValidMethods([]string{"HS256", "ES256"})),
		jwt.SigningMethodES256,
	},
	{
		"JSON Number",
		"",
		defaultKeyFunc,
		jwt.MapClaims{"foo": json.Number("123.4")},
		true,
		nil,
		jwt.NewParser(jwt.WithJSONNumber()),
		jwt.SigningMethodRS256,
	},
	{
		"JSON Number - basic expired",
		"", // autogen
		defaultKeyFunc,
		jwt.MapClaims{"foo": "bar", "exp": json.Number(fmt.Sprintf("%v", time.Now().Unix()-100))},
		false,
		[]error{jwt.ErrTokenExpired},
		jwt.NewParser(jwt.WithJSONNumber()),
		jwt.SigningMethodRS256,
	},
	{
		"JSON Number - basic nbf",
		"", // autogen
		defaultKeyFunc,
		jwt.MapClaims{"foo": "bar", "nbf": json.Number(fmt.Sprintf("%v", time.Now().Unix()+100))},
		false,
		[]error{jwt.ErrTokenNotValidYet},
		jwt.NewParser(jwt.WithJSONNumber()),
		jwt.SigningMethodRS256,
	},
	{
		"JSON Number - expired and nbf",
		"", // autogen
		defaultKeyFunc,
		jwt.MapClaims{"foo": "bar", "nbf": json.Number(fmt.Sprintf("%v", time.Now().Unix()+100)), "exp": json.Number(fmt.Sprintf("%v", time.Now().Unix()-100))},
		false,
		[]error{jwt.ErrTokenNotValidYet, jwt.ErrTokenExpired},
		jwt.NewParser(jwt.WithJSONNumber()),
		jwt.SigningMethodRS256,
	},
	{
		"SkipClaimsValidation during token parsing",
		"", // autogen
		defaultKeyFunc,
		jwt.MapClaims{"foo": "bar", "nbf": json.Number(fmt.Sprintf("%v", time.Now().Unix()+100))},
		true,
		nil,
		jwt.NewParser(jwt.WithJSONNumber(), jwt.WithoutClaimsValidation()),
		jwt.SigningMethodRS256,
	},
	{
		"RFC7519 Claims",
		"",
		defaultKeyFunc,
		&jwt.RegisteredClaims{
			ExpiresAt: jwt.NewNumericDate(time.Now().Add(time.Second * 10)),
		},
		true,
		nil,
		jwt.NewParser(jwt.WithJSONNumber()),
		jwt.SigningMethodRS256,
	},
	{
		"RFC7519 Claims - single aud",
		"",
		defaultKeyFunc,
		&jwt.RegisteredClaims{
			Audience: jwt.ClaimStrings{"test"},
		},
		true,
		nil,
		jwt.NewParser(jwt.WithJSONNumber()),
		jwt.SigningMethodRS256,
	},
	{
		"RFC7519 Claims - multiple aud",
		"",
		defaultKeyFunc,
		&jwt.RegisteredClaims{
			Audience: jwt.ClaimStrings{"test", "test"},
		},
		true,
		nil,
		jwt.NewParser(jwt.WithJSONNumber()),
		jwt.SigningMethodRS256,
	},
	{
		"RFC7519 Claims - single aud with wrong type",
		"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOjF9.8mAIDUfZNQT3TGm1QFIQp91OCpJpQpbB1-m9pA2mkHc", // { "aud": 1 }
		defaultKeyFunc,
		&jwt.RegisteredClaims{
			Audience: nil, // because of the unmarshal error, this will be empty
		},
		false,
		[]error{jwt.ErrTokenMalformed},
		jwt.NewParser(jwt.WithJSONNumber()),
		jwt.SigningMethodRS256,
	},
	{
		"RFC7519 Claims - multiple aud with wrong types",
		"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsidGVzdCIsMV19.htEBUf7BVbfSmVoTFjXf3y6DLmDUuLy1vTJ14_EX7Ws", // { "aud": ["test", 1] }
		defaultKeyFunc,
		&jwt.RegisteredClaims{
			Audience: nil, // because of the unmarshal error, this will be empty
		},
		false,
		[]error{jwt.ErrTokenMalformed},
		jwt.NewParser(jwt.WithJSONNumber()),
		jwt.SigningMethodRS256,
	},
	{
		"RFC7519 Claims - nbf with 60s skew",
		"", // autogen
		defaultKeyFunc,
		&jwt.RegisteredClaims{NotBefore: jwt.NewNumericDate(time.Now().Add(time.Second * 100))},
		false,
		[]error{jwt.ErrTokenNotValidYet},
		jwt.NewParser(jwt.WithLeeway(time.Minute)),
		jwt.SigningMethodRS256,
	},
	{
		"RFC7519 Claims - nbf with 120s skew",
		"", // autogen
		defaultKeyFunc,
		&jwt.RegisteredClaims{NotBefore: jwt.NewNumericDate(time.Now().Add(time.Second * 100))},
		true,
		nil,
		jwt.NewParser(jwt.WithLeeway(2 * time.Minute)),
		jwt.SigningMethodRS256,
	},
	{
		"rejects if exp is required but missing",
		"", // autogen
		defaultKeyFunc,
		&jwt.RegisteredClaims{},
		false,
		[]error{jwt.ErrTokenInvalidClaims},
		jwt.NewParser(jwt.WithExpirationRequired()),
		jwt.SigningMethodRS256,
	},
}

// signToken creates and returns a signed JWT token using signingMethod.
func signToken(claims jwt.Claims, signingMethod jwt.SigningMethod) string {
	var privateKey any
	switch signingMethod {
	case jwt.SigningMethodRS256:
		privateKey = jwtTestRSAPrivateKey
	case jwt.SigningMethodES256:
		privateKey = jwtTestEC256PrivateKey
	default:
		return ""
	}
	return test.MakeSampleToken(claims, signingMethod, privateKey)
}

func TestParser_Parse(t *testing.T) {
	// Iterate over test data set and run tests
	for _, data := range jwtTestData {
		t.Run(data.name, func(t *testing.T) {
			// If the token string is blank, use helper function to generate string
			if data.tokenString == "" {
				data.tokenString = signToken(data.claims, data.signingMethod)
			}

			// Parse the token
			var token *jwt.Token
			var err error
			var parser = data.parser
			if parser == nil {
				parser = jwt.NewParser()
			}
			// Figure out correct claims type
			switch data.claims.(type) {
			case jwt.MapClaims:
				token, err = parser.ParseWithClaims(data.tokenString, jwt.MapClaims{}, data.keyfunc)
			case *jwt.RegisteredClaims:
				token, err = parser.ParseWithClaims(data.tokenString, &jwt.RegisteredClaims{}, data.keyfunc)
			case *customClaimsWithDifferentTypes:
				token, err = parser.ParseWithClaims(data.tokenString, &customClaimsWithDifferentTypes{}, data.keyfunc)
			case nil:
				token, err = parser.ParseWithClaims(data.tokenString, nil, data.keyfunc)
			}

			// Verify result matches expectation
			if data.claims != nil && !reflect.DeepEqual(data.claims, token.Claims) {
				t.Errorf("[%v] Claims mismatch. Expecting: %v  Got: %v", data.name, data.claims, token.Claims)
			}

			if data.valid && err != nil {
				t.Errorf("[%v] Error while verifying token: %T:%v", data.name, err, err)
			}

			if !data.valid && err == nil {
				t.Errorf("[%v] Invalid token passed validation", data.name)
			}

			// Since the returned token is nil in the ErrTokenMalformed, we
			// cannot make the comparison here
			if !errors.Is(err, jwt.ErrTokenMalformed) &&
				((err == nil && !token.Valid) || (err != nil && token.Valid)) {
				t.Errorf("[%v] Inconsistent behavior between returned error and token.Valid", data.name)
			}

			if data.err != nil {
				if err == nil {
					t.Errorf("[%v] Expecting error(s). Didn't get one.", data.name)
				} else {
					var all = false
					for _, e := range data.err {
						all = errors.Is(err, e)
					}

					if !all {
						t.Errorf("[%v] Errors don't match expectation.  %v should contain all of %v", data.name, err, data.err)
					}
				}
			}

			if data.valid {
				if len(token.Signature) == 0 {
					t.Errorf("[%v] Signature is left unpopulated after parsing", data.name)
				}
				if !token.Valid {
					// The 'Valid' field should be set to true when invoking Parse()
					t.Errorf("[%v] Token.Valid field mismatch. Expecting true, got %v", data.name, token.Valid)
				}
			}
		})
	}
}

func TestParser_ParseUnverified(t *testing.T) {
	// Iterate over test data set and run tests
	for _, data := range jwtTestData {
		// Skip test data, that intentionally contains malformed tokens, as they would lead to an error
		if len(data.err) == 1 && errors.Is(data.err[0], jwt.ErrTokenMalformed) {
			continue
		}

		t.Run(data.name, func(t *testing.T) {
			// If the token string is blank, use helper function to generate string
			if data.tokenString == "" {
				data.tokenString = signToken(data.claims, data.signingMethod)
			}

			// Parse the token
			var token *jwt.Token
			var err error
			var parser = data.parser
			if parser == nil {
				parser = new(jwt.Parser)
			}
			// Figure out correct claims type
			switch data.claims.(type) {
			case jwt.MapClaims:
				token, _, err = parser.ParseUnverified(data.tokenString, jwt.MapClaims{})
			case *jwt.RegisteredClaims:
				token, _, err = parser.ParseUnverified(data.tokenString, &jwt.RegisteredClaims{})
			case *customClaimsWithDifferentTypes:
				token, _, err = parser.ParseUnverified(data.tokenString, &customClaimsWithDifferentTypes{})
			}

			if err != nil {
				t.Errorf("[%v] Invalid token", data.name)
			}

			// Verify result matches expectation
			if !reflect.DeepEqual(data.claims, token.Claims) {
				t.Errorf("[%v] Claims mismatch. Expecting: %v  Got: %v", data.name, data.claims, token.Claims)
			}

			if data.valid && err != nil {
				t.Errorf("[%v] Error while verifying token: %T:%v", data.name, err, err)
			}
			if token.Valid {
				// The 'Valid' field should not be set to true when invoking ParseUnverified()
				t.Errorf("[%v] Token.Valid field mismatch. Expecting false, got %v", data.name, token.Valid)
			}
			if len(token.Signature) == 0 {
				// The 'Signature' should always be populated.
				t.Errorf("[%v] Token.Signature field mismatch. Expecting non-nil, got %v", data.name, token.Signature)
			}
		})
	}
}

var setPaddingTestData = []struct {
	name          string
	tokenString   string
	claims        jwt.Claims
	paddedDecode  bool
	strictDecode  bool
	signingMethod jwt.SigningMethod
	keyfunc       jwt.Keyfunc
	valid         bool
}{
	{
		name:          "Validated non-padded token with padding disabled",
		tokenString:   "",
		claims:        jwt.MapClaims{"foo": "paddedbar"},
		paddedDecode:  false,
		signingMethod: jwt.SigningMethodRS256,
		keyfunc:       defaultKeyFunc,
		valid:         true,
	},
	{
		name:          "Validated non-padded token with padding enabled",
		tokenString:   "",
		claims:        jwt.MapClaims{"foo": "paddedbar"},
		paddedDecode:  true,
		signingMethod: jwt.SigningMethodRS256,
		keyfunc:       defaultKeyFunc,
		valid:         true,
	},
	{
		name:          "Error for padded token with padding disabled",
		tokenString:   "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJwYWRkZWRiYXIifQ==.20kGGJaYekGTRFf8b0TwhuETcR8lv5z2363X5jf7G1yTWVTwOmte5Ii8L8_OQbYwPoiVHmZY6iJPbt_DhCN42AeFY74BcsUhR-BVrYUVhKK0RppuzEcSlILDNeQsJDLEL035CPm1VO6Jrgk7enQPIctVxUesRgswP71OpGvJxy3j1k_J8p0WzZvRZTe1D_2Misa0UDGwnEIHhmr97fIpMSZjFxlcygQw8QN34IHLHIXMaTY1eiCf4CCr6rOS9wUeu7P3CPkmFq9XhxBT_LLCmIMhHnxP5x27FUJE_JZlfek0MmARcrhpsZS2sFhHAiWrjxjOE27jkDtv1nEwn65wMw==",
		claims:        jwt.MapClaims{"foo": "paddedbar"},
		paddedDecode:  false,
		signingMethod: jwt.SigningMethodRS256,
		keyfunc:       defaultKeyFunc,
		valid:         false,
	},
	{
		name:          "Validated padded token with padding enabled",
		tokenString:   "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJwYWRkZWRiYXIifQ==.20kGGJaYekGTRFf8b0TwhuETcR8lv5z2363X5jf7G1yTWVTwOmte5Ii8L8_OQbYwPoiVHmZY6iJPbt_DhCN42AeFY74BcsUhR-BVrYUVhKK0RppuzEcSlILDNeQsJDLEL035CPm1VO6Jrgk7enQPIctVxUesRgswP71OpGvJxy3j1k_J8p0WzZvRZTe1D_2Misa0UDGwnEIHhmr97fIpMSZjFxlcygQw8QN34IHLHIXMaTY1eiCf4CCr6rOS9wUeu7P3CPkmFq9XhxBT_LLCmIMhHnxP5x27FUJE_JZlfek0MmARcrhpsZS2sFhHAiWrjxjOE27jkDtv1nEwn65wMw==",
		claims:        jwt.MapClaims{"foo": "paddedbar"},
		paddedDecode:  true,
		signingMethod: jwt.SigningMethodRS256,
		keyfunc:       defaultKeyFunc,
		valid:         true,
	},
	{
		name:          "Error for example padded token with padding disabled",
		tokenString:   "eyJ0eXAiOiJKV1QiLCJraWQiOiIxMjM0NTY3OC1hYmNkLTEyMzQtYWJjZC0xMjM0NTY3OGFiY2QiLCJhbGciOiJFUzI1NiIsImlzcyI6Imh0dHBzOi8vY29nbml0by1pZHAuZXUtd2VzdC0yLmFtYXpvbmF3cy5jb20vIiwiY2xpZW50IjoiN0xUY29QWnJWNDR6ZVg2WUs5VktBcHZPM3EiLCJzaWduZXIiOiJhcm46YXdzOmVsYXN0aWNsb2FkYmFsYW5jaW5nIiwiZXhwIjoxNjI5NDcwMTAxfQ==.eyJzdWIiOiIxMjM0NTY3OC1hYmNkLTEyMzQtYWJjZC0xMjM0NTY3OGFiY2QiLCJlbWFpbF92ZXJpZmllZCI6InRydWUiLCJlbWFpbCI6InVzZXJAZXhhbXBsZS5jb20iLCJ1c2VybmFtZSI6IjEyMzQ1Njc4LWFiY2QtMTIzNC1hYmNkLTEyMzQ1Njc4YWJjZCIsImV4cCI6MTYyOTQ3MDEwMSwiaXNzIjoiaHR0cHM6Ly9jb2duaXRvLWlkcC5ldS13ZXN0LTIuYW1hem9uYXdzLmNvbS8ifQ==.sx0muJ754glJvwWgkHaPrOI3L1gaPjRLLUvOQRk0WitnqC5Dtt1knorcbOzlEcH9zwPM2jYYIAYQz_qEyM3grw==",
		claims:        nil,
		paddedDecode:  false,
		signingMethod: jwt.SigningMethodES256,
		keyfunc:       paddedKeyFunc,
		valid:         false,
	},
	{
		name:          "Validated example padded token with padding enabled",
		tokenString:   "eyJ0eXAiOiJKV1QiLCJraWQiOiIxMjM0NTY3OC1hYmNkLTEyMzQtYWJjZC0xMjM0NTY3OGFiY2QiLCJhbGciOiJFUzI1NiIsImlzcyI6Imh0dHBzOi8vY29nbml0by1pZHAuZXUtd2VzdC0yLmFtYXpvbmF3cy5jb20vIiwiY2xpZW50IjoiN0xUY29QWnJWNDR6ZVg2WUs5VktBcHZPM3EiLCJzaWduZXIiOiJhcm46YXdzOmVsYXN0aWNsb2FkYmFsYW5jaW5nIiwiZXhwIjoxNjI5NDcwMTAxfQ==.eyJzdWIiOiIxMjM0NTY3OC1hYmNkLTEyMzQtYWJjZC0xMjM0NTY3OGFiY2QiLCJlbWFpbF92ZXJpZmllZCI6InRydWUiLCJlbWFpbCI6InVzZXJAZXhhbXBsZS5jb20iLCJ1c2VybmFtZSI6IjEyMzQ1Njc4LWFiY2QtMTIzNC1hYmNkLTEyMzQ1Njc4YWJjZCIsImV4cCI6MTYyOTQ3MDEwMSwiaXNzIjoiaHR0cHM6Ly9jb2duaXRvLWlkcC5ldS13ZXN0LTIuYW1hem9uYXdzLmNvbS8ifQ==.sx0muJ754glJvwWgkHaPrOI3L1gaPjRLLUvOQRk0WitnqC5Dtt1knorcbOzlEcH9zwPM2jYYIAYQz_qEyM3grw==",
		claims:        nil,
		paddedDecode:  true,
		signingMethod: jwt.SigningMethodES256,
		keyfunc:       paddedKeyFunc,
		valid:         true,
	},
	// DecodeStrict tests, DecodePaddingAllowed=false
	{
		name: "Validated non-padded token with padding disabled, non-strict decode, non-tweaked signature",
		tokenString: "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJwYWRkZWRiYXIifQ.bI15h-7mN0f-2diX5I4ErgNQy1uM-rJS5Sz7O0iTWtWSBxY1h6wy8Ywxe5EZTEO6GiIfk7Lk-72Ex-c5aA40QKhPwWB9BJ8O_LfKpezUVBOn0jRItDnVdsk4ccl2zsOVkbA4U4QvdrSbOYMbwoRHzDXfTFpoeMWtn3ez0aENJ8dh4E1echHp5ByI9Pu2aBsvM1WVcMt_BySweCL3f4T7jNZeXDr7Txd00yUd2gdsHYPjXorOvsgaBKN5GLsWd1zIY5z-2gCC8CRSN-IJ4NNX5ifh7l-bOXE2q7szTqa9pvyE9y6TQJhNMSE2FotRce_TOPBWgGpQ-K2I7E8x7wZ8O" +
			"g",
		claims:        nil,
		paddedDecode:  false,
		strictDecode:  false,
		signingMethod: jwt.SigningMethodRS256,
		keyfunc:       defaultKeyFunc,
		valid:         true,
	},
	{
		name: "Validated non-padded token with padding disabled, non-strict decode, tweaked signature",
		tokenString: "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJwYWRkZWRiYXIifQ.bI15h-7mN0f-2diX5I4ErgNQy1uM-rJS5Sz7O0iTWtWSBxY1h6wy8Ywxe5EZTEO6GiIfk7Lk-72Ex-c5aA40QKhPwWB9BJ8O_LfKpezUVBOn0jRItDnVdsk4ccl2zsOVkbA4U4QvdrSbOYMbwoRHzDXfTFpoeMWtn3ez0aENJ8dh4E1echHp5ByI9Pu2aBsvM1WVcMt_BySweCL3f4T7jNZeXDr7Txd00yUd2gdsHYPjXorOvsgaBKN5GLsWd1zIY5z-2gCC8CRSN-IJ4NNX5ifh7l-bOXE2q7szTqa9pvyE9y6TQJhNMSE2FotRce_TOPBWgGpQ-K2I7E8x7wZ8O" +
			"h",
		claims:        nil,
		paddedDecode:  false,
		strictDecode:  false,
		signingMethod: jwt.SigningMethodRS256,
		keyfunc:       defaultKeyFunc,
		valid:         true,
	},
	{
		name: "Validated non-padded token with padding disabled, strict decode, non-tweaked signature",
		tokenString: "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJwYWRkZWRiYXIifQ.bI15h-7mN0f-2diX5I4ErgNQy1uM-rJS5Sz7O0iTWtWSBxY1h6wy8Ywxe5EZTEO6GiIfk7Lk-72Ex-c5aA40QKhPwWB9BJ8O_LfKpezUVBOn0jRItDnVdsk4ccl2zsOVkbA4U4QvdrSbOYMbwoRHzDXfTFpoeMWtn3ez0aENJ8dh4E1echHp5ByI9Pu2aBsvM1WVcMt_BySweCL3f4T7jNZeXDr7Txd00yUd2gdsHYPjXorOvsgaBKN5GLsWd1zIY5z-2gCC8CRSN-IJ4NNX5ifh7l-bOXE2q7szTqa9pvyE9y6TQJhNMSE2FotRce_TOPBWgGpQ-K2I7E8x7wZ8O" +
			"g",
		claims:        nil,
		paddedDecode:  false,
		strictDecode:  true,
		signingMethod: jwt.SigningMethodRS256,
		keyfunc:       defaultKeyFunc,
		valid:         true,
	},
	{
		name: "Error for non-padded token with padding disabled, strict decode, tweaked signature",
		tokenString: "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJwYWRkZWRiYXIifQ.bI15h-7mN0f-2diX5I4ErgNQy1uM-rJS5Sz7O0iTWtWSBxY1h6wy8Ywxe5EZTEO6GiIfk7Lk-72Ex-c5aA40QKhPwWB9BJ8O_LfKpezUVBOn0jRItDnVdsk4ccl2zsOVkbA4U4QvdrSbOYMbwoRHzDXfTFpoeMWtn3ez0aENJ8dh4E1echHp5ByI9Pu2aBsvM1WVcMt_BySweCL3f4T7jNZeXDr7Txd00yUd2gdsHYPjXorOvsgaBKN5GLsWd1zIY5z-2gCC8CRSN-IJ4NNX5ifh7l-bOXE2q7szTqa9pvyE9y6TQJhNMSE2FotRce_TOPBWgGpQ-K2I7E8x7wZ8O" +
			"h",
		claims:        nil,
		paddedDecode:  false,
		strictDecode:  true,
		signingMethod: jwt.SigningMethodRS256,
		keyfunc:       defaultKeyFunc,
		valid:         false,
	},
	// DecodeStrict tests, DecodePaddingAllowed=true
	{
		name: "Validated padded token with padding enabled, non-strict decode, non-tweaked signature",
		tokenString: "eyJ0eXAiOiJKV1QiLCJraWQiOiIxMjM0NTY3OC1hYmNkLTEyMzQtYWJjZC0xMjM0NTY3OGFiY2QiLCJhbGciOiJFUzI1NiIsImlzcyI6Imh0dHBzOi8vY29nbml0by1pZHAuZXUtd2VzdC0yLmFtYXpvbmF3cy5jb20vIiwiY2xpZW50IjoiN0xUY29QWnJWNDR6ZVg2WUs5VktBcHZPM3EiLCJzaWduZXIiOiJhcm46YXdzOmVsYXN0aWNsb2FkYmFsYW5jaW5nIiwiZXhwIjoxNjI5NDcwMTAxfQ==.eyJzdWIiOiIxMjM0NTY3OC1hYmNkLTEyMzQtYWJjZC0xMjM0NTY3OGFiY2QiLCJlbWFpbF92ZXJpZmllZCI6InRydWUiLCJlbWFpbCI6InVzZXJAZXhhbXBsZS5jb20iLCJ1c2VybmFtZSI6IjEyMzQ1Njc4LWFiY2QtMTIzNC1hYmNkLTEyMzQ1Njc4YWJjZCIsImV4cCI6MTYyOTQ3MDEwMSwiaXNzIjoiaHR0cHM6Ly9jb2duaXRvLWlkcC5ldS13ZXN0LTIuYW1hem9uYXdzLmNvbS8ifQ==.sx0muJ754glJvwWgkHaPrOI3L1gaPjRLLUvOQRk0WitnqC5Dtt1knorcbOzlEcH9zwPM2jYYIAYQz_qEyM3gr" +
			"w==",
		claims:        nil,
		paddedDecode:  true,
		strictDecode:  false,
		signingMethod: jwt.SigningMethodES256,
		keyfunc:       paddedKeyFunc,
		valid:         true,
	},
	{
		name: "Validated padded token with padding enabled, non-strict decode, tweaked signature",
		tokenString: "eyJ0eXAiOiJKV1QiLCJraWQiOiIxMjM0NTY3OC1hYmNkLTEyMzQtYWJjZC0xMjM0NTY3OGFiY2QiLCJhbGciOiJFUzI1NiIsImlzcyI6Imh0dHBzOi8vY29nbml0by1pZHAuZXUtd2VzdC0yLmFtYXpvbmF3cy5jb20vIiwiY2xpZW50IjoiN0xUY29QWnJWNDR6ZVg2WUs5VktBcHZPM3EiLCJzaWduZXIiOiJhcm46YXdzOmVsYXN0aWNsb2FkYmFsYW5jaW5nIiwiZXhwIjoxNjI5NDcwMTAxfQ==.eyJzdWIiOiIxMjM0NTY3OC1hYmNkLTEyMzQtYWJjZC0xMjM0NTY3OGFiY2QiLCJlbWFpbF92ZXJpZmllZCI6InRydWUiLCJlbWFpbCI6InVzZXJAZXhhbXBsZS5jb20iLCJ1c2VybmFtZSI6IjEyMzQ1Njc4LWFiY2QtMTIzNC1hYmNkLTEyMzQ1Njc4YWJjZCIsImV4cCI6MTYyOTQ3MDEwMSwiaXNzIjoiaHR0cHM6Ly9jb2duaXRvLWlkcC5ldS13ZXN0LTIuYW1hem9uYXdzLmNvbS8ifQ==.sx0muJ754glJvwWgkHaPrOI3L1gaPjRLLUvOQRk0WitnqC5Dtt1knorcbOzlEcH9zwPM2jYYIAYQz_qEyM3gr" +
			"x==",
		claims:        nil,
		paddedDecode:  true,
		strictDecode:  false,
		signingMethod: jwt.SigningMethodES256,
		keyfunc:       paddedKeyFunc,
		valid:         true,
	},
	{
		name: "Validated padded token with padding enabled, strict decode, non-tweaked signature",
		tokenString: "eyJ0eXAiOiJKV1QiLCJraWQiOiIxMjM0NTY3OC1hYmNkLTEyMzQtYWJjZC0xMjM0NTY3OGFiY2QiLCJhbGciOiJFUzI1NiIsImlzcyI6Imh0dHBzOi8vY29nbml0by1pZHAuZXUtd2VzdC0yLmFtYXpvbmF3cy5jb20vIiwiY2xpZW50IjoiN0xUY29QWnJWNDR6ZVg2WUs5VktBcHZPM3EiLCJzaWduZXIiOiJhcm46YXdzOmVsYXN0aWNsb2FkYmFsYW5jaW5nIiwiZXhwIjoxNjI5NDcwMTAxfQ==.eyJzdWIiOiIxMjM0NTY3OC1hYmNkLTEyMzQtYWJjZC0xMjM0NTY3OGFiY2QiLCJlbWFpbF92ZXJpZmllZCI6InRydWUiLCJlbWFpbCI6InVzZXJAZXhhbXBsZS5jb20iLCJ1c2VybmFtZSI6IjEyMzQ1Njc4LWFiY2QtMTIzNC1hYmNkLTEyMzQ1Njc4YWJjZCIsImV4cCI6MTYyOTQ3MDEwMSwiaXNzIjoiaHR0cHM6Ly9jb2duaXRvLWlkcC5ldS13ZXN0LTIuYW1hem9uYXdzLmNvbS8ifQ==.sx0muJ754glJvwWgkHaPrOI3L1gaPjRLLUvOQRk0WitnqC5Dtt1knorcbOzlEcH9zwPM2jYYIAYQz_qEyM3gr" +
			"w==",
		claims:        nil,
		paddedDecode:  true,
		strictDecode:  true,
		signingMethod: jwt.SigningMethodES256,
		keyfunc:       paddedKeyFunc,
		valid:         true,
	},
	{
		name: "Error for padded token with padding enabled, strict decode, tweaked signature",
		tokenString: "eyJ0eXAiOiJKV1QiLCJraWQiOiIxMjM0NTY3OC1hYmNkLTEyMzQtYWJjZC0xMjM0NTY3OGFiY2QiLCJhbGciOiJFUzI1NiIsImlzcyI6Imh0dHBzOi8vY29nbml0by1pZHAuZXUtd2VzdC0yLmFtYXpvbmF3cy5jb20vIiwiY2xpZW50IjoiN0xUY29QWnJWNDR6ZVg2WUs5VktBcHZPM3EiLCJzaWduZXIiOiJhcm46YXdzOmVsYXN0aWNsb2FkYmFsYW5jaW5nIiwiZXhwIjoxNjI5NDcwMTAxfQ==.eyJzdWIiOiIxMjM0NTY3OC1hYmNkLTEyMzQtYWJjZC0xMjM0NTY3OGFiY2QiLCJlbWFpbF92ZXJpZmllZCI6InRydWUiLCJlbWFpbCI6InVzZXJAZXhhbXBsZS5jb20iLCJ1c2VybmFtZSI6IjEyMzQ1Njc4LWFiY2QtMTIzNC1hYmNkLTEyMzQ1Njc4YWJjZCIsImV4cCI6MTYyOTQ3MDEwMSwiaXNzIjoiaHR0cHM6Ly9jb2duaXRvLWlkcC5ldS13ZXN0LTIuYW1hem9uYXdzLmNvbS8ifQ==.sx0muJ754glJvwWgkHaPrOI3L1gaPjRLLUvOQRk0WitnqC5Dtt1knorcbOzlEcH9zwPM2jYYIAYQz_qEyM3gr" +
			"x==",
		claims:        nil,
		paddedDecode:  true,
		strictDecode:  true,
		signingMethod: jwt.SigningMethodES256,
		keyfunc:       paddedKeyFunc,
		valid:         false,
	},
}

// Extension of Parsing, this is to test out functionality specific to switching codecs with padding.
func TestSetPadding(t *testing.T) {
	for _, data := range setPaddingTestData {
		t.Run(data.name, func(t *testing.T) {
			// If the token string is blank, use helper function to generate string
			if data.tokenString == "" {
				data.tokenString = signToken(data.claims, data.signingMethod)
			}

			// Parse the token
			var token *jwt.Token
			var err error
			var opts = []jwt.ParserOption{jwt.WithoutClaimsValidation()}

			if data.paddedDecode {
				opts = append(opts, jwt.WithPaddingAllowed())
			}
			if data.strictDecode {
				opts = append(opts, jwt.WithStrictDecoding())
			}

			parser := jwt.NewParser(opts...)

			// Figure out correct claims type
			token, err = parser.ParseWithClaims(data.tokenString, jwt.MapClaims{}, data.keyfunc)

			if (err == nil) != data.valid || token.Valid != data.valid {
				t.Errorf("[%v] Error Parsing Token with decoding padding set to %v: %v",
					data.name,
					data.paddedDecode,
					err,
				)
			}
		})
	}
}

func BenchmarkParseUnverified(b *testing.B) {
	// Iterate over test data set and run tests
	for _, data := range jwtTestData {
		// If the token string is blank, use helper function to generate string
		if data.tokenString == "" {
			data.tokenString = signToken(data.claims, data.signingMethod)
		}

		// Parse the token
		var parser = data.parser
		if parser == nil {
			parser = new(jwt.Parser)
		}
		// Figure out correct claims type
		switch data.claims.(type) {
		case jwt.MapClaims:
			b.Run("map_claims", func(b *testing.B) {
				benchmarkParsing(b, parser, data.tokenString, jwt.MapClaims{})
			})
		case *jwt.RegisteredClaims:
			b.Run("registered_claims", func(b *testing.B) {
				benchmarkParsing(b, parser, data.tokenString, &jwt.RegisteredClaims{})
			})
		}
	}
}

// Helper method for benchmarking various parsing methods
func benchmarkParsing(b *testing.B, parser *jwt.Parser, tokenString string, claims jwt.Claims) {
	b.Helper()
	b.ReportAllocs()
	b.ResetTimer()
	b.RunParallel(func(pb *testing.PB) {
		for pb.Next() {
			_, _, err := parser.ParseUnverified(tokenString, jwt.MapClaims{})
			if err != nil {
				b.Fatal(err)
			}
		}
	})
}

// Helper method for benchmarking various signing methods
func benchmarkSigning(b *testing.B, method jwt.SigningMethod, key any) {
	b.Helper()
	t := jwt.New(method)
	b.ReportAllocs()
	b.ResetTimer()
	b.RunParallel(func(pb *testing.PB) {
		for pb.Next() {
			if _, err := t.SignedString(key); err != nil {
				b.Fatal(err)
			}
		}
	})
}


================================================
FILE: registered_claims.go
================================================
package jwt

// RegisteredClaims are a structured version of the JWT Claims Set,
// restricted to Registered Claim Names, as referenced at
// https://datatracker.ietf.org/doc/html/rfc7519#section-4.1
//
// This type can be used on its own, but then additional private and
// public claims embedded in the JWT will not be parsed. The typical use-case
// therefore is to embedded this in a user-defined claim type.
//
// See examples for how to use this with your own claim types.
type RegisteredClaims struct {
	// the `iss` (Issuer) claim. See https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.1
	Issuer string `json:"iss,omitempty"`

	// the `sub` (Subject) claim. See https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.2
	Subject string `json:"sub,omitempty"`

	// the `aud` (Audience) claim. See https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.3
	Audience ClaimStrings `json:"aud,omitempty"`

	// the `exp` (Expiration Time) claim. See https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.4
	ExpiresAt *NumericDate `json:"exp,omitempty"`

	// the `nbf` (Not Before) claim. See https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.5
	NotBefore *NumericDate `json:"nbf,omitempty"`

	// the `iat` (Issued At) claim. See https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.6
	IssuedAt *NumericDate `json:"iat,omitempty"`

	// the `jti` (JWT ID) claim. See https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.7
	ID string `json:"jti,omitempty"`
}

// GetExpirationTime implements the Claims interface.
func (c RegisteredClaims) GetExpirationTime() (*NumericDate, error) {
	return c.ExpiresAt, nil
}

// GetNotBefore implements the Claims interface.
func (c RegisteredClaims) GetNotBefore() (*NumericDate, error) {
	return c.NotBefore, nil
}

// GetIssuedAt implements the Claims interface.
func (c RegisteredClaims) GetIssuedAt() (*NumericDate, error) {
	return c.IssuedAt, nil
}

// GetAudience implements the Claims interface.
func (c RegisteredClaims) GetAudience() (ClaimStrings, error) {
	return c.Audience, nil
}

// GetIssuer implements the Claims interface.
func (c RegisteredClaims) GetIssuer() (string, error) {
	return c.Issuer, nil
}

// GetSubject implements the Claims interface.
func (c RegisteredClaims) GetSubject() (string, error) {
	return c.Subject, nil
}


================================================
FILE: request/doc.go
================================================
// Utility package for extracting JWT tokens from
// HTTP requests.
//
// The main function is ParseFromRequest and it's WithClaims variant.
// See examples for how to use the various Extractor implementations
// or roll your own.
package request


================================================
FILE: request/extractor.go
================================================
package request

import (
	"errors"
	"net/http"
	"strings"
)

// Errors
var (
	ErrNoTokenInRequest = errors.New("no token present in request")
)

// Extractor is an interface for extracting a token from an HTTP request.
// The ExtractToken method should return a token string or an error.
// If no token is present, you must return ErrNoTokenInRequest.
type Extractor interface {
	ExtractToken(*http.Request) (string, error)
}

// HeaderExtractor is an extractor for finding a token in a header.
// Looks at each specified header in order until there's a match
type HeaderExtractor []string

func (e HeaderExtractor) ExtractToken(req *http.Request) (string, error) {
	// loop over header names and return the first one that contains data
	for _, header := range e {
		if ah := req.Header.Get(header); ah != "" {
			return ah, nil
		}
	}
	return "", ErrNoTokenInRequest
}

// ArgumentExtractor extracts a token from request arguments.  This includes a POSTed form or
// GET URL arguments.  Argument names are tried in order until there's a match.
// This extractor calls `ParseMultipartForm` on the request
type ArgumentExtractor []string

func (e ArgumentExtractor) ExtractToken(req *http.Request) (string, error) {
	// Make sure form is parsed. We are explicitly ignoring errors at this point
	_ = req.ParseMultipartForm(10e6)

	// loop over arg names and return the first one that contains data
	for _, arg := range e {
		if ah := req.Form.Get(arg); ah != "" {
			return ah, nil
		}
	}

	return "", ErrNoTokenInRequest
}

// MultiExtractor tries Extractors in order until one returns a token string or an error occurs
type MultiExtractor []Extractor

func (e MultiExtractor) ExtractToken(req *http.Request) (string, error) {
	// loop over header names and return the first one that contains data
	for _, extractor := range e {
		if tok, err := extractor.ExtractToken(req); tok != "" {
			return tok, nil
		} else if !errors.Is(err, ErrNoTokenInRequest) {
			return "", err
		}
	}
	return "", ErrNoTokenInRequest
}

// PostExtractionFilter wraps an Extractor in this to post-process the value before it's handed off.
// See AuthorizationHeaderExtractor for an example
type PostExtractionFilter struct {
	Extractor
	Filter func(string) (string, error)
}

func (e *PostExtractionFilter) ExtractToken(req *http.Request) (string, error) {
	if tok, err := e.Extractor.ExtractToken(req); tok != "" {
		return e.Filter(tok)
	} else {
		return "", err
	}
}

// BearerExtractor extracts a token from the Authorization header.
// The header is expected to match the format "Bearer XX", where "XX" is the
// JWT token.
type BearerExtractor struct{}

func (e BearerExtractor) ExtractToken(req *http.Request) (string, error) {
	tokenHeader := req.Header.Get("Authorization")
	// The usual convention is for "Bearer" to be title-cased. However, there's no
	// strict rule around this, and it's best to follow the robustness principle here.
	if len(tokenHeader) < 7 || !strings.EqualFold(tokenHeader[:7], "bearer ") {
		return "", ErrNoTokenInRequest
	}
	return tokenHeader[7:], nil
}


================================================
FILE: request/extractor_example_test.go
================================================
package request

import (
	"fmt"
	"net/url"
)

const (
	exampleTokenA = "A"
)

func ExampleHeaderExtractor() {
	req := makeExampleRequest("GET", "/", map[string]string{"Token": exampleTokenA}, nil)
	tokenString, err := HeaderExtractor{"Token"}.ExtractToken(req)
	if err == nil {
		fmt.Println(tokenString)
	} else {
		fmt.Println(err)
	}
	// Output: A
}

func ExampleArgumentExtractor() {
	req := makeExampleRequest("GET", "/", nil, url.Values{"token": {extractorTestTokenA}})
	tokenString, err := ArgumentExtractor{"token"}.ExtractToken(req)
	if err == nil {
		fmt.Println(tokenString)
	} else {
		fmt.Println(err)
	}
	// Output: A
}


================================================
FILE: request/extractor_test.go
================================================
package request

import (
	"fmt"
	"net/http"
	"net/url"
	"testing"
)

var extractorTestTokenA = "A"
var extractorTestTokenB = "B"

var extractorTestData = []struct {
	name      string
	extractor Extractor
	headers   map[string]string
	query     url.Values
	token     string
	err       error
}{
	{
		name:      "simple header",
		extractor: HeaderExtractor{"Foo"},
		headers:   map[string]string{"Foo": extractorTestTokenA},
		query:     nil,
		token:     extractorTestTokenA,
		err:       nil,
	},
	{
		name:      "simple argument",
		extractor: ArgumentExtractor{"token"},
		headers:   map[string]string{},
		query:     url.Values{"token": {extractorTestTokenA}},
		token:     extractorTestTokenA,
		err:       nil,
	},
	{
		name: "multiple extractors",
		extractor: MultiExtractor{
			HeaderExtractor{"Foo"},
			ArgumentExtractor{"token"},
		},
		headers: map[string]string{"Foo": extractorTestTokenA},
		query:   url.Values{"token": {extractorTestTokenB}},
		token:   extractorTestTokenA,
		err:     nil,
	},
	{
		name:      "simple miss",
		extractor: HeaderExtractor{"This-Header-Is-Not-Set"},
		headers:   map[string]string{"Foo": extractorTestTokenA},
		query:     nil,
		token:     "",
		err:       ErrNoTokenInRequest,
	},
	{
		name:      "filter",
		extractor: AuthorizationHeaderExtractor,
		headers:   map[string]string{"Authorization": "Bearer " + extractorTestTokenA},
		query:     nil,
		token:     extractorTestTokenA,
		err:       nil,
	},
}

func TestExtractor(t *testing.T) {
	// Bearer token request
	for _, data := range extractorTestData {
		// Make request from test struct
		r := makeExampleRequest("GET", "/", data.headers, data.query)

		// Test extractor
		token, err := data.extractor.ExtractToken(r)
		if token != data.token {
			t.Errorf("[%v] Expected token '%v'.  Got '%v'", data.name, data.token, token)
			continue
		}
		if err != data.err {
			t.Errorf("[%v] Expected error '%v'.  Got '%v'", data.name, data.err, err)
			continue
		}
	}
}

func makeExampleRequest(method, path string, headers map[string]string, urlArgs url.Values) *http.Request {
	r, _ := http.NewRequest(method, fmt.Sprintf("%v?%v", path, urlArgs.Encode()), nil)
	for k, v := range headers {
		r.Header.Set(k, v)
	}
	return r
}

func TestBearerExtractor(t *testing.T) {
	request := makeExampleRequest("POST", "https://example.com/", map[string]string{"Authorization": "Bearer ToKen"}, nil)
	token, err := BearerExtractor{}.ExtractToken(request)
	if err != nil || token != "ToKen" {
		t.Errorf("ExtractToken did not return token, returned: %v, %v", token, err)
	}

	request = makeExampleRequest("POST", "https://example.com/", map[string]string{"Authorization": "Bearo ToKen"}, nil)
	token, err = BearerExtractor{}.ExtractToken(request)
	if err == nil || token != "" {
		t.Errorf("ExtractToken did not return error, returned: %v, %v", token, err)
	}

	request = makeExampleRequest("POST", "https://example.com/", map[string]string{"Authorization": "BeArEr HeLO"}, nil)
	token, err = BearerExtractor{}.ExtractToken(request)
	if err != nil || token != "HeLO" {
		t.Errorf("ExtractToken did not return token, returned: %v, %v", token, err)
	}
}


================================================
FILE: request/oauth2.go
================================================
package request

import (
	"strings"
)

// Strips 'Bearer ' prefix from bearer token string
func stripBearerPrefixFromTokenString(tok string) (string, error) {
	// Should be a bearer token
	if len(tok) > 6 && strings.EqualFold(tok[:7], "bearer ") {
		return tok[7:], nil
	}
	return tok, nil
}

// AuthorizationHeaderExtractor extracts a bearer token from Authorization header
// Uses PostExtractionFilter to strip "Bearer " prefix from header
var AuthorizationHeaderExtractor = &PostExtractionFilter{
	HeaderExtractor{"Authorization"},
	stripBearerPrefixFromTokenString,
}

// OAuth2Extractor is an Extractor for OAuth2 access tokens.  Looks in 'Authorization'
// header then 'access_token' argument for a token.
var OAuth2Extractor = &MultiExtractor{
	AuthorizationHeaderExtractor,
	ArgumentExtractor{"access_token"},
}


================================================
FILE: request/request.go
================================================
package request

import (
	"net/http"

	"github.com/golang-jwt/jwt/v5"
)

// ParseFromRequest extracts and parses a JWT token from an HTTP request.
// This behaves the same as Parse, but accepts a request and an extractor
// instead of a token string.  The Extractor interface allows you to define
// the logic for extracting a token.  Several useful implementations are provided.
//
// You can provide options to modify parsing behavior
func ParseFromRequest(req *http.Request, extractor Extractor, keyFunc jwt.Keyfunc, options ...ParseFromRequestOption) (token *jwt.Token, err error) {
	// Create basic parser struct
	p := &fromRequestParser{req, extractor, nil, nil}

	// Handle options
	for _, option := range options {
		option(p)
	}

	// Set defaults
	if p.claims == nil {
		p.claims = jwt.MapClaims{}
	}
	if p.parser == nil {
		p.parser = &jwt.Parser{}
	}

	// perform extract
	tokenString, err := p.extractor.ExtractToken(req)
	if err != nil {
		return nil, err
	}

	// perform parse
	return p.parser.ParseWithClaims(tokenString, p.claims, keyFunc)
}

// ParseFromRequestWithClaims is an alias for ParseFromRequest but with custom Claims type.
//
// Deprecated: use ParseFromRequest and the WithClaims option
func ParseFromRequestWithClaims(req *http.Request, extractor Extractor, claims jwt.Claims, keyFunc jwt.Keyfunc) (token *jwt.Token, err error) {
	return ParseFromRequest(req, extractor, keyFunc, WithClaims(claims))
}

type fromRequestParser struct {
	req       *http.Request
	extractor Extractor
	claims    jwt.Claims
	parser    *jwt.Parser
}

type ParseFromRequestOption func(*fromRequestParser)

// WithClaims parses with custom claims
func WithClaims(claims jwt.Claims) ParseFromRequestOption {
	return func(p *fromRequestParser) {
		p.claims = claims
	}
}

// WithParser parses using a custom parser
func WithParser(parser *jwt.Parser) ParseFromRequestOption {
	return func(p *fromRequestParser) {
		p.parser = parser
	}
}


================================================
FILE: request/request_test.go
================================================
package request

import (
	"fmt"
	"net/http"
	"net/url"
	"reflect"
	"strings"
	"testing"

	"github.com/golang-jwt/jwt/v5"
	"github.com/golang-jwt/jwt/v5/test"
)

var requestTestData = []struct {
	name      string
	claims    jwt.MapClaims
	extractor Extractor
	headers   map[string]string
	query     url.Values
	valid     bool
}{
	{
		"authorization bearer token",
		jwt.MapClaims{"foo": "bar"},
		AuthorizationHeaderExtractor,
		map[string]string{"Authorization": "Bearer %v"},
		url.Values{},
		true,
	},
	{
		"oauth bearer token - header",
		jwt.MapClaims{"foo": "bar"},
		OAuth2Extractor,
		map[string]string{"Authorization": "Bearer %v"},
		url.Values{},
		true,
	},
	{
		"oauth bearer token - url",
		jwt.MapClaims{"foo": "bar"},
		OAuth2Extractor,
		map[string]string{},
		url.Values{"access_token": {"%v"}},
		true,
	},
	{
		"url token",
		jwt.MapClaims{"foo": "bar"},
		ArgumentExtractor{"token"},
		map[string]string{},
		url.Values{"token": {"%v"}},
		true,
	},
}

func TestParseRequest(t *testing.T) {
	// load keys from disk
	privateKey := test.LoadRSAPrivateKeyFromDisk("../test/sample_key")
	publicKey := test.LoadRSAPublicKeyFromDisk("../test/sample_key.pub")
	keyfunc := func(*jwt.Token) (any, error) {
		return publicKey, nil
	}

	// Bearer token request
	for _, data := range requestTestData {
		// Make token from claims
		tokenString := test.MakeSampleToken(data.claims, jwt.SigningMethodRS256, privateKey)

		// Make query string
		for k, vv := range data.query {
			for i, v := range vv {
				if strings.Contains(v, "%v") {
					data.query[k][i] = fmt.Sprintf(v, tokenString)
				}
			}
		}

		// Make request from test struct
		r, _ := http.NewRequest("GET", fmt.Sprintf("/?%v", data.query.Encode()), nil)
		for k, v := range data.headers {
			if strings.Contains(v, "%v") {
				r.Header.Set(k, fmt.Sprintf(v, tokenString))
			} else {
				r.Header.Set(k, tokenString)
			}
		}
		token, err := ParseFromRequestWithClaims(r, data.extractor, jwt.MapClaims{}, keyfunc)

		if token == nil {
			t.Errorf("[%v] Token was not found: %v", data.name, err)
			continue
		}
		if !reflect.DeepEqual(data.claims, token.Claims) {
			t.Errorf("[%v] Claims mismatch. Expecting: %v  Got: %v", data.name, data.claims, token.Claims)
		}
		if data.valid && err != nil {
			t.Errorf("[%v] Error while verifying token: %v", data.name, err)
		}
		if !data.valid && err == nil {
			t.Errorf("[%v] Invalid token passed validation", data.name)
		}
	}
}


================================================
FILE: rsa.go
================================================
package jwt

import (
	"crypto"
	"crypto/rand"
	"crypto/rsa"
)

// SigningMethodRSA implements the RSA family of signing methods.
// Expects *rsa.PrivateKey for signing and *rsa.PublicKey for validation
type SigningMethodRSA struct {
	Name string
	Hash crypto.Hash
}

// Specific instances for RS256 and company
var (
	SigningMethodRS256 *SigningMethodRSA
	SigningMethodRS384 *SigningMethodRSA
	SigningMethodRS512 *SigningMethodRSA
)

func init() {
	// RS256
	SigningMethodRS256 = &SigningMethodRSA{"RS256", crypto.SHA256}
	RegisterSigningMethod(SigningMethodRS256.Alg(), func() SigningMethod {
		return SigningMethodRS256
	})

	// RS384
	SigningMethodRS384 = &SigningMethodRSA{"RS384", crypto.SHA384}
	RegisterSigningMethod(SigningMethodRS384.Alg(), func() SigningMethod {
		return SigningMethodRS384
	})

	// RS512
	SigningMethodRS512 = &SigningMethodRSA{"RS512", crypto.SHA512}
	RegisterSigningMethod(SigningMethodRS512.Alg(), func() SigningMethod {
		return SigningMethodRS512
	})
}

func (m *SigningMethodRSA) Alg() string {
	return m.Name
}

// Verify implements token verification for the SigningMethod
// For this signing method, must be an *rsa.PublicKey structure.
func (m *SigningMethodRSA) Verify(signingString string, sig []byte, key any) error {
	var rsaKey *rsa.PublicKey
	var ok bool

	if rsaKey, ok = key.(*rsa.PublicKey); !ok {
		return newError("RSA verify expects *rsa.PublicKey", ErrInvalidKeyType)
	}

	// Create hasher
	if !m.Hash.Available() {
		return ErrHashUnavailable
	}
	hasher := m.Hash.New()
	hasher.Write([]byte(signingString))

	// Verify the signature
	return rsa.VerifyPKCS1v15(rsaKey, m.Hash, hasher.Sum(nil), sig)
}

// Sign implements token signing for the SigningMethod
// For this signing method, must be an *rsa.PrivateKey structure.
func (m *SigningMethodRSA) Sign(signingString string, key any) ([]byte, error) {
	var rsaKey *rsa.PrivateKey
	var ok bool

	// Validate type of key
	if rsaKey, ok = key.(*rsa.PrivateKey); !ok {
		return nil, newError("RSA sign expects *rsa.PrivateKey", ErrInvalidKeyType)
	}

	// Create the hasher
	if !m.Hash.Available() {
		return nil, ErrHashUnavailable
	}

	hasher := m.Hash.New()
	hasher.Write([]byte(signingString))

	// Sign the string and return the encoded bytes
	if sigBytes, err := rsa.SignPKCS1v15(rand.Reader, rsaKey, m.Hash, hasher.Sum(nil)); err == nil {
		return sigBytes, nil
	} else {
		return nil, err
	}
}


================================================
FILE: rsa_pss.go
================================================
package jwt

import (
	"crypto"
	"crypto/rand"
	"crypto/rsa"
)

// SigningMethodRSAPSS implements the RSAPSS family of signing methods signing methods
type SigningMethodRSAPSS struct {
	*SigningMethodRSA
	Options *rsa.PSSOptions
	// VerifyOptions is optional. If set overrides Options for rsa.VerifyPPS.
	// Used to accept tokens signed with rsa.PSSSaltLengthAuto, what doesn't follow
	// https://tools.ietf.org/html/rfc7518#section-3.5 but was used previously.
	// See https://github.com/dgrijalva/jwt-go/issues/285#issuecomment-437451244 for details.
	VerifyOptions *rsa.PSSOptions
}

// Specific instances for RS/PS and company.
var (
	SigningMethodPS256 *SigningMethodRSAPSS
	SigningMethodPS384 *SigningMethodRSAPSS
	SigningMethodPS512 *SigningMethodRSAPSS
)

func init() {
	// PS256
	SigningMethodPS256 = &SigningMethodRSAPSS{
		SigningMethodRSA: &SigningMethodRSA{
			Name: "PS256",
			Hash: crypto.SHA256,
		},
		Options: &rsa.PSSOptions{
			SaltLength: rsa.PSSSaltLengthEqualsHash,
		},
		VerifyOptions: &rsa.PSSOptions{
			SaltLength: rsa.PSSSaltLengthAuto,
		},
	}
	RegisterSigningMethod(SigningMethodPS256.Alg(), func() SigningMethod {
		return SigningMethodPS256
	})

	// PS384
	SigningMethodPS384 = &SigningMethodRSAPSS{
		SigningMethodRSA: &SigningMethodRSA{
			Name: "PS384",
			Hash: crypto.SHA384,
		},
		Options: &rsa.PSSOptions{
			SaltLength: rsa.PSSSaltLengthEqualsHash,
		},
		VerifyOptions: &rsa.PSSOptions{
			SaltLength: rsa.PSSSaltLengthAuto,
		},
	}
	RegisterSigningMethod(SigningMethodPS384.Alg(), func() SigningMethod {
		return SigningMethodPS384
	})

	// PS512
	SigningMethodPS512 = &SigningMethodRSAPSS{
		SigningMethodRSA: &SigningMethodRSA{
			Name: "PS512",
			Hash: crypto.SHA512,
		},
		Options: &rsa.PSSOptions{
			SaltLength: rsa.PSSSaltLengthEqualsHash,
		},
		VerifyOptions: &rsa.PSSOptions{
			SaltLength: rsa.PSSSaltLengthAuto,
		},
	}
	RegisterSigningMethod(SigningMethodPS512.Alg(), func() SigningMethod {
		return SigningMethodPS512
	})
}

// Verify implements token verification for the SigningMethod.
// For this verify method, key must be an rsa.PublicKey struct
func (m *SigningMethodRSAPSS) Verify(signingString string, sig []byte, key any) error {
	var rsaKey *rsa.PublicKey
	switch k := key.(type) {
	case *rsa.PublicKey:
		rsaKey = k
	default:
		return newError("RSA-PSS verify expects *rsa.PublicKey", ErrInvalidKeyType)
	}

	// Create hasher
	if !m.Hash.Available() {
		return ErrHashUnavailable
	}
	hasher := m.Hash.New()
	hasher.Write([]byte(signingString))

	opts := m.Options
	if m.VerifyOptions != nil {
		opts = m.VerifyOptions
	}

	return rsa.VerifyPSS(rsaKey, m.Hash, hasher.Sum(nil), sig, opts)
}

// Sign implements token signing for the SigningMethod.
// For this signing method, key must be an rsa.PrivateKey struct
func (m *SigningMethodRSAPSS) Sign(signingString string, key any) ([]byte, error) {
	var rsaKey *rsa.PrivateKey

	switch k := key.(type) {
	case *rsa.PrivateKey:
		rsaKey = k
	default:
		return nil, newError("RSA-PSS sign expects *rsa.PrivateKey", ErrInvalidKeyType)
	}

	// Create the hasher
	if !m.Hash.Available() {
		return nil, ErrHashUnavailable
	}

	hasher := m.Hash.New()
	hasher.Write([]byte(signingString))

	// Sign the string and return the encoded bytes
	if sigBytes, err := rsa.SignPSS(rand.Reader, rsaKey, m.Hash, hasher.Sum(nil), m.Options); err == nil {
		return sigBytes, nil
	} else {
		return nil, err
	}
}


================================================
FILE: rsa_pss_test.go
================================================
package jwt_test

import (
	"crypto/rsa"
	"os"
	"strings"
	"testing"
	"time"

	"github.com/golang-jwt/jwt/v5"
	"github.com/golang-jwt/jwt/v5/test"
)

var rsaPSSTestData = []struct {
	name        string
	tokenString string
	alg         string
	claims      map[string]any
	valid       bool
}{
	{
		"Basic PS256",
		"eyJhbGciOiJQUzI1NiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJiYXIifQ.PPG4xyDVY8ffp4CcxofNmsTDXsrVG2npdQuibLhJbv4ClyPTUtR5giNSvuxo03kB6I8VXVr0Y9X7UxhJVEoJOmULAwRWaUsDnIewQa101cVhMa6iR8X37kfFoiZ6NkS-c7henVkkQWu2HtotkEtQvN5hFlk8IevXXPmvZlhQhwzB1sGzGYnoi1zOfuL98d3BIjUjtlwii5w6gYG2AEEzp7HnHCsb3jIwUPdq86Oe6hIFjtBwduIK90ca4UqzARpcfwxHwVLMpatKask00AgGVI0ysdk0BLMjmLutquD03XbThHScC2C2_Pp4cHWgMzvbgLU2RYYZcZRKr46QeNgz9w",
		"PS256",
		map[string]any{"foo": "bar"},
		true,
	},
	{
		"Basic PS384",
		"eyJhbGciOiJQUzM4NCIsInR5cCI6IkpXVCJ9.eyJmb28iOiJiYXIifQ.w7-qqgj97gK4fJsq_DCqdYQiylJjzWONvD0qWWWhqEOFk2P1eDULPnqHRnjgTXoO4HAw4YIWCsZPet7nR3Xxq4ZhMqvKW8b7KlfRTb9cH8zqFvzMmybQ4jv2hKc3bXYqVow3AoR7hN_CWXI3Dv6Kd2X5xhtxRHI6IL39oTVDUQ74LACe-9t4c3QRPuj6Pq1H4FAT2E2kW_0KOc6EQhCLWEhm2Z2__OZskDC8AiPpP8Kv4k2vB7l0IKQu8Pr4RcNBlqJdq8dA5D3hk5TLxP8V5nG1Ib80MOMMqoS3FQvSLyolFX-R_jZ3-zfq6Ebsqr0yEb0AH2CfsECF7935Pa0FKQ",
		"PS384",
		map[string]any{"foo": "bar"},
		true,
	},
	{
		"Basic PS512",
		"eyJhbGciOiJQUzUxMiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJiYXIifQ.GX1HWGzFaJevuSLavqqFYaW8_TpvcjQ8KfC5fXiSDzSiT9UD9nB_ikSmDNyDILNdtjZLSvVKfXxZJqCfefxAtiozEDDdJthZ-F0uO4SPFHlGiXszvKeodh7BuTWRI2wL9-ZO4mFa8nq3GMeQAfo9cx11i7nfN8n2YNQ9SHGovG7_T_AvaMZB_jT6jkDHpwGR9mz7x1sycckEo6teLdHRnH_ZdlHlxqknmyTu8Odr5Xh0sJFOL8BepWbbvIIn-P161rRHHiDWFv6nhlHwZnVzjx7HQrWSGb6-s2cdLie9QL_8XaMcUpjLkfOMKkDOfHo6AvpL7Jbwi83Z2ZTHjJWB-A",
		"PS512",
		map[string]any{"foo": "bar"},
		true,
	},
	{
		"basic PS256 invalid: foo => bar",
		"eyJhbGciOiJQUzI1NiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJiYXIifQ.PPG4xyDVY8ffp4CcxofNmsTDXsrVG2npdQuibLhJbv4ClyPTUtR5giNSvuxo03kB6I8VXVr0Y9X7UxhJVEoJOmULAwRWaUsDnIewQa101cVhMa6iR8X37kfFoiZ6NkS-c7henVkkQWu2HtotkEtQvN5hFlk8IevXXPmvZlhQhwzB1sGzGYnoi1zOfuL98d3BIjUjtlwii5w6gYG2AEEzp7HnHCsb3jIwUPdq86Oe6hIFjtBwduIK90ca4UqzARpcfwxHwVLMpatKask00AgGVI0ysdk0BLMjmLutquD03XbThHScC2C2_Pp4cHWgMzvbgLU2RYYZcZRKr46QeNgz9W",
		"PS256",
		map[string]any{"foo": "bar"},
		false,
	},
}

func TestRSAPSSVerify(t *testing.T) {
	var err error

	key, _ := os.ReadFile("test/sample_key.pub")
	var rsaPSSKey *rsa.PublicKey
	if rsaPSSKey, err = jwt.ParseRSAPublicKeyFromPEM(key); err != nil {
		t.Errorf("Unable to parse RSA public key: %v", err)
	}

	for _, data := range rsaPSSTestData {
		parts := strings.Split(data.tokenString, ".")

		method := jwt.GetSigningMethod(data.alg)
		err := method.Verify(strings.Join(parts[0:2], "."), decodeSegment(t, parts[2]), rsaPSSKey)
		if data.valid && err != nil {
			t.Errorf("[%v] Error while verifying key: %v", data.name, err)
		}
		if !data.valid && err == nil {
			t.Errorf("[%v] Invalid key passed validation", data.name)
		}
	}
}

func TestRSAPSSSign(t *testing.T) {
	var err error

	key, _ := os.ReadFile("test/sample_key")
	var rsaPSSKey *rsa.PrivateKey
	if rsaPSSKey, err = jwt.ParseRSAPrivateKeyFromPEM(key); err != nil {
		t.Errorf("Unable to parse RSA private key: %v", err)
	}

	for _, data := range rsaPSSTestData {
		if !data.valid {
			continue
		}
		parts := strings.Split(data.tokenString, ".")
		method := jwt.GetSigningMethod(data.alg)
		sig, err := method.Sign(strings.Join(parts[0:2], "."), rsaPSSKey)
		if err != nil {
			t.Errorf("[%v] Error signing token: %v", data.name, err)
		}

		ssig := encodeSegment(sig)
		if ssig == parts[2] {
			t.Errorf("[%v] Signatures shouldn't match\nnew:\n%v\noriginal:\n%v", data.name, ssig, parts[2])
		}
	}
}

func TestRSAPSSSaltLengthCompatibility(t *testing.T) {
	// Fails token verify, if salt length is auto.
	ps256SaltLengthEqualsHash := &jwt.SigningMethodRSAPSS{
		SigningMethodRSA: jwt.SigningMethodPS256.SigningMethodRSA,
		Options: &rsa.PSSOptions{
			SaltLength: rsa.PSSSaltLengthEqualsHash,
		},
	}

	// Behaves as before https://github.com/dgrijalva/jwt-go/issues/285 fix.
	ps256SaltLengthAuto := &jwt.SigningMethodRSAPSS{
		SigningMethodRSA: jwt.SigningMethodPS256.SigningMethodRSA,
		Options: &rsa.PSSOptions{
			SaltLength: rsa.PSSSaltLengthAuto,
		},
	}
	if !verify(t, jwt.SigningMethodPS256, makeToken(ps256SaltLengthEqualsHash)) {
		t.Error("SigningMethodPS256 should accept salt length that is defined in RFC")
	}
	if !verify(t, ps256SaltLengthEqualsHash, makeToken(jwt.SigningMethodPS256)) {
		t.Error("Sign by SigningMethodPS256 should have salt length that is defined in RFC")
	}
	if !verify(t, jwt.SigningMethodPS256, makeToken(ps256SaltLengthAuto)) {
		t.Error("SigningMethodPS256 should accept auto salt length to be compatible with previous versions")
	}
	if !verify(t, ps256SaltLengthAuto, makeToken(jwt.SigningMethodPS256)) {
		t.Error("Sign by SigningMethodPS256 should be accepted by previous versions")
	}
	if verify(t, ps256SaltLengthEqualsHash, makeToken(ps256SaltLengthAuto)) {
		t.Error("Auto salt length should be not accepted, when RFC salt length is required")
	}
}

func makeToken(method jwt.SigningMethod) string {
	token := jwt.NewWithClaims(method, jwt.RegisteredClaims{
		Issuer:   "example",
		IssuedAt: jwt.NewNumericDate(time.Now()),
	})
	privateKey := test.LoadRSAPrivateKeyFromDisk("test/sample_key")
	signed, err := token.SignedString(privateKey)
	if err != nil {
		panic(err)
	}
	return signed
}

func verify(t *testing.T, signingMethod jwt.SigningMethod, token string) bool {
	segments := strings.Split(token, ".")
	err := signingMethod.Verify(strings.Join(segments[:2], "."), decodeSegment(t, segments[2]), test.LoadRSAPublicKeyFromDisk("test/sample_key.pub"))
	return err == nil
}


================================================
FILE: rsa_test.go
================================================
package jwt_test

import (
	"bytes"
	"crypto/rand"
	"crypto/rsa"
	"crypto/x509"
	"encoding/pem"
	"os"
	"reflect"
	"strings"
	"testing"

	"github.com/golang-jwt/jwt/v5"
)

var rsaTestData = []struct {
	name        string
	tokenString string
	alg         string
	valid       bool
}{
	{
		"Basic RS256",
		"eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJmb28iOiJiYXIifQ.FhkiHkoESI_cG3NPigFrxEk9Z60_oXrOT2vGm9Pn6RDgYNovYORQmmA0zs1AoAOf09ly2Nx2YAg6ABqAYga1AcMFkJljwxTT5fYphTuqpWdy4BELeSYJx5Ty2gmr8e7RonuUztrdD5WfPqLKMm1Ozp_T6zALpRmwTIW0QPnaBXaQD90FplAg46Iy1UlDKr-Eupy0i5SLch5Q-p2ZpaL_5fnTIUDlxC3pWhJTyx_71qDI-mAA_5lE_VdroOeflG56sSmDxopPEG3bFlSu1eowyBfxtu0_CuVd-M42RU75Zc4Gsj6uV77MBtbMrf4_7M_NUTSgoIF3fRqxrj0NzihIBg",
		"RS256",
		true,
	},
	{
		"Basic RS384",
		"eyJhbGciOiJSUzM4NCIsInR5cCI6IkpXVCJ9.eyJmb28iOiJiYXIifQ.W-jEzRfBigtCWsinvVVuldiuilzVdU5ty0MvpLaSaqK9PlAWWlDQ1VIQ_qSKzwL5IXaZkvZFJXT3yL3n7OUVu7zCNJzdwznbC8Z-b0z2lYvcklJYi2VOFRcGbJtXUqgjk2oGsiqUMUMOLP70TTefkpsgqDxbRh9CDUfpOJgW-dU7cmgaoswe3wjUAUi6B6G2YEaiuXC0XScQYSYVKIzgKXJV8Zw-7AN_DBUI4GkTpsvQ9fVVjZM9csQiEXhYekyrKu1nu_POpQonGd8yqkIyXPECNmmqH5jH4sFiF67XhD7_JpkvLziBpI-uh86evBUadmHhb9Otqw3uV3NTaXLzJw",
		"RS384",
		true,
	},
	{
		"Basic RS512",
		"eyJhbGciOiJSUzUxMiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJiYXIifQ.zBlLlmRrUxx4SJPUbV37Q1joRcI9EW13grnKduK3wtYKmDXbgDpF1cZ6B-2Jsm5RB8REmMiLpGms-EjXhgnyh2TSHE-9W2gA_jvshegLWtwRVDX40ODSkTb7OVuaWgiy9y7llvcknFBTIg-FnVPVpXMmeV_pvwQyhaz1SSwSPrDyxEmksz1hq7YONXhXPpGaNbMMeDTNP_1oj8DZaqTIL9TwV8_1wb2Odt_Fy58Ke2RVFijsOLdnyEAjt2n9Mxihu9i3PhNBkkxa2GbnXBfq3kzvZ_xxGGopLdHhJjcGWXO-NiwI9_tiu14NRv4L2xC0ItD9Yz68v2ZIZEp_DuzwRQ",
		"RS512",
		true,
	},
	{
		"basic invalid: foo => bar",
		"eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJmb28iOiJiYXIifQ.EhkiHkoESI_cG3NPigFrxEk9Z60_oXrOT2vGm9Pn6RDgYNovYORQmmA0zs1AoAOf09ly2Nx2YAg6ABqAYga1AcMFkJljwxTT5fYphTuqpWdy4BELeSYJx5Ty2gmr8e7RonuUztrdD5WfPqLKMm1Ozp_T6zALpRmwTIW0QPnaBXaQD90FplAg46Iy1UlDKr-Eupy0i5SLch5Q-p2ZpaL_5fnTIUDlxC3pWhJTyx_71qDI-mAA_5lE_VdroOeflG56sSmDxopPEG3bFlSu1eowyBfxtu0_CuVd-M42RU75Zc4Gsj6uV77MBtbMrf4_7M_NUTSgoIF3fRqxrj0NzihIBg",
		"RS256",
		false,
	},
}

func TestRSAVerify(t *testing.T) {
	keyData, _ := os.ReadFile("test/sample_key.pub")
	key, _ := jwt.ParseRSAPublicKeyFromPEM(keyData)

	for _, data := range rsaTestData {
		parts := strings.Split(data.tokenString, ".")

		method := jwt.GetSigningMethod(data.alg)
		err := method.Verify(strings.Join(parts[0:2], "."), decodeSegment(t, parts[2]), key)
		if data.valid && err != nil {
			t.Errorf("[%v] Error while verifying key: %v", data.name, err)
		}
		if !data.valid && err == nil {
			t.Errorf("[%v] Invalid key passed validation", data.name)
		}
	}
}

func TestRSASign(t *testing.T) {
	keyData, _ := os.ReadFile("test/sample_key")
	key, _ := jwt.ParseRSAPrivateKeyFromPEM(keyData)

	for _, data := range rsaTestData {
		if data.valid {
			parts := strings.Split(data.tokenString, ".")
			method := jwt.GetSigningMethod(data.alg)
			sig, err := method.Sign(strings.Join(parts[0:2], "."), key)
			if err != nil {
				t.Errorf("[%v] Error signing token: %v", data.name, err)
			}
			if !reflect.DeepEqual(sig, decodeSegment(t, parts[2])) {
				t.Errorf("[%v] Incorrect signature.\nwas:\n%v\nexpecting:\n%v", data.name, sig, parts[2])
			}
		}
	}
}

func TestRSAVerifyWithPreParsedPrivateKey(t *testing.T) {
	key, _ := os.ReadFile("test/sample_key.pub")
	parsedKey, err := jwt.ParseRSAPublicKeyFromPEM(key)
	if err != nil {
		t.Fatal(err)
	}
	testData := rsaTestData[0]
	parts := strings.Split(testData.tokenString, ".")
	err = jwt.SigningMethodRS256.Verify(strings.Join(parts[0:2], "."), decodeSegment(t, parts[2]), parsedKey)
	if err != nil {
		t.Errorf("[%v] Error while verifying key: %v", testData.name, err)
	}
}

func TestRSAWithPreParsedPrivateKey(t *testing.T) {
	key, _ := os.ReadFile("test/sample_key")
	parsedKey, err := jwt.ParseRSAPrivateKeyFromPEM(key)
	if err != nil {
		t.Fatal(err)
	}
	testData := rsaTestData[0]
	parts := strings.Split(testData.tokenString, ".")
	sig, err := jwt.SigningMethodRS256.Sign(strings.Join(parts[0:2], "."), parsedKey)
	if err != nil {
		t.Errorf("[%v] Error signing token: %v", testData.name, err)
	}
	if !reflect.DeepEqual(sig, decodeSegment(t, parts[2])) {
		t.Errorf("[%v] Incorrect signature.\nwas:\n%v\nexpecting:\n%v", testData.name, sig, parts[2])
	}
}

func TestRSAKeyParsing(t *testing.T) {
	key, _ := os.ReadFile("test/sample_key")
	secureKey, _ := os.ReadFile("test/privateSecure.pem")
	pubKey, _ := os.ReadFile("test/sample_key.pub")
	badKey := []byte("All your base are belong to key")

	randomKey, err := rsa.GenerateKey(rand.Reader, 2048)
	if err != nil {
		t.Errorf("Failed to generate RSA private key: %v", err)
	}

	publicKeyBytes := x509.MarshalPKCS1PublicKey(&randomKey.PublicKey)
	pkcs1Buffer := new(bytes.Buffer)
	if err = pem.Encode(pkcs1Buffer, &pem.Block{Type: "RSA PUBLIC KEY", Bytes: publicKeyBytes}); err != nil {
		t.Errorf("Failed to encode public pem: %v", err)
	}

	// Test parsePrivateKey
	if _, e := jwt.ParseRSAPrivateKeyFromPEM(key); e != nil {
		t.Errorf("Failed to parse valid private key: %v", e)
	}

	if k, e := jwt.ParseRSAPrivateKeyFromPEM(pubKey); e == nil {
		t.Errorf("Parsed public key as valid private key: %v", k)
	}

	if k, e := jwt.ParseRSAPrivateKeyFromPEM(badKey); e == nil {
		t.Errorf("Parsed invalid key as valid private key: %v", k)
	}

	if _, e := jwt.ParseRSAPrivateKeyFromPEMWithPassword(secureKey, "password"); e != nil {
		t.Errorf("Failed to parse valid private key with password: %v", e)
	}

	if k, e := jwt.ParseRSAPrivateKeyFromPEMWithPassword(secureKey, "123132"); e == nil {
		t.Errorf("Parsed private key with invalid password %v", k)
	}

	// Test parsePublicKey
	if _, e := jwt.ParseRSAPublicKeyFromPEM(pubKey); e != nil {
		t.Errorf("Failed to parse valid public key: %v", e)
	}

	if k, e := jwt.ParseRSAPublicKeyFromPEM(key); e == nil {
		t.Errorf("Parsed private key as valid public key: %v", k)
	}

	if k, e := jwt.ParseRSAPublicKeyFromPEM(badKey); e == nil {
		t.Errorf("Parsed invalid key as valid private key: %v", k)
	}

	if _, err := jwt.ParseRSAPublicKeyFromPEM(pkcs1Buffer.Bytes()); err != nil {
		t.Errorf("failed to parse RSA public key: %v", err)
	}
}

func BenchmarkRSAParsing(b *testing.B) {
	key, _ := os.ReadFile("test/sample_key")

	b.ReportAllocs()
	b.ResetTimer()
	b.RunParallel(func(pb *testing.PB) {
		for pb.Next() {
			if _, err := jwt.ParseRSAPrivateKeyFromPEM(key); err != nil {
				b.Fatalf("Unable to parse RSA private key: %v", err)
			}
		}
	})
}

func BenchmarkRS256Signing(b *testing.B) {
	key, _ := os.ReadFile("test/sample_key")
	parsedKey, err := jwt.ParseRSAPrivateKeyFromPEM(key)
	if err != nil {
		b.Fatal(err)
	}

	benchmarkSigning(b, jwt.SigningMethodRS256, parsedKey)
}

func BenchmarkRS384Signing(b *testing.B) {
	key, _ := os.ReadFile("test/sample_key")
	parsedKey, err := jwt.ParseRSAPrivateKeyFromPEM(key)
	if err != nil {
		b.Fatal(err)
	}

	benchmarkSigning(b, jwt.SigningMethodRS384, parsedKey)
}

func BenchmarkRS512Signing(b *testing.B) {
	key, _ := os.ReadFile("test/sample_key")
	parsedKey, err := jwt.ParseRSAPrivateKeyFromPEM(key)
	if err != nil {
		b.Fatal(err)
	}

	benchmarkSigning(b, jwt.SigningMethodRS512, parsedKey)
}


================================================
FILE: rsa_utils.go
================================================
package jwt

import (
	"crypto/rsa"
	"crypto/x509"
	"encoding/pem"
	"errors"
)

var (
	ErrKeyMustBePEMEncoded = errors.New("invalid key: Key must be a PEM encoded PKCS1 or PKCS8 key")
	ErrNotRSAPrivateKey    = errors.New("key is not a valid RSA private key")
	ErrNotRSAPublicKey     = errors.New("key is not a valid RSA public key")
)

// ParseRSAPrivateKeyFromPEM parses a PEM encoded PKCS1 or PKCS8 private key
func ParseRSAPrivateKeyFromPEM(key []byte) (*rsa.PrivateKey, error) {
	var err error

	// Parse PEM block
	var block *pem.Block
	if block, _ = pem.Decode(key); block == nil {
		return nil, ErrKeyMustBePEMEncoded
	}

	var parsedKey any
	if parsedKey, err = x509.ParsePKCS1PrivateKey(block.Bytes); err != nil {
		if parsedKey, err = x509.ParsePKCS8PrivateKey(block.Bytes); err != nil {
			return nil, err
		}
	}

	var pkey *rsa.PrivateKey
	var ok bool
	if pkey, ok = parsedKey.(*rsa.PrivateKey); !ok {
		return nil, ErrNotRSAPrivateKey
	}

	return pkey, nil
}

// ParseRSAPrivateKeyFromPEMWithPassword parses a PEM encoded PKCS1 or PKCS8 private key protected with password
//
// Deprecated: This function is deprecated and should not be used anymore. It uses the deprecated x509.DecryptPEMBlock
// function, which was deprecated since RFC 1423 is regarded insecure by design. Unfortunately, there is no alternative
// in the Go standard library for now. See https://github.com/golang/go/issues/8860.
func ParseRSAPrivateKeyFromPEMWithPassword(key []byte, password string) (*rsa.PrivateKey, error) {
	var err error

	// Parse PEM block
	var block *pem.Block
	if block, _ = pem.Decode(key); block == nil {
		return nil, ErrKeyMustBePEMEncoded
	}

	var parsedKey any

	var blockDecrypted []byte
	if blockDecrypted, err = x509.DecryptPEMBlock(block, []byte(password)); err != nil {
		return nil, err
	}

	if parsedKey, err = x509.ParsePKCS1PrivateKey(blockDecrypted); err != nil {
		if parsedKey, err = x509.ParsePKCS8PrivateKey(blockDecrypted); err != nil {
			return nil, err
		}
	}

	var pkey *rsa.PrivateKey
	var ok bool
	if pkey, ok = parsedKey.(*rsa.PrivateKey); !ok {
		return nil, ErrNotRSAPrivateKey
	}

	return pkey, nil
}

// ParseRSAPublicKeyFromPEM parses a certificate or a PEM encoded PKCS1 or PKIX public key
func ParseRSAPublicKeyFromPEM(key []byte) (*rsa.PublicKey, error) {
	var err error

	// Parse PEM block
	var block *pem.Block
	if block, _ = pem.Decode(key); block == nil {
		return nil, ErrKeyMustBePEMEncoded
	}

	// Parse the key
	var parsedKey any
	if parsedKey, err = x509.ParsePKIXPublicKey(block.Bytes); err != nil {
		if cert, err := x509.ParseCertificate(block.Bytes); err == nil {
			parsedKey = cert.PublicKey
		} else {
			if parsedKey, err = x509.ParsePKCS1PublicKey(block.Bytes); err != nil {
				return nil, err
			}
		}
	}

	var pkey *rsa.PublicKey
	var ok bool
	if pkey, ok = parsedKey.(*rsa.PublicKey); !ok {
		return nil, ErrNotRSAPublicKey
	}

	return pkey, nil
}


================================================
FILE: signing_method.go
================================================
package jwt

import (
	"sync"
)

var signingMethods = map[string]func() SigningMethod{}
var signingMethodLock = new(sync.RWMutex)

// SigningMethod can be used add new methods for signing or verifying tokens. It
// takes a decoded signature as an input in the Verify function and produces a
// signature in Sign. The signature is then usually base64 encoded as part of a
// JWT.
type SigningMethod interface {
	Verify(signingString string, sig []byte, key any) error // Returns nil if signature is valid
	Sign(signingString string, key any) ([]byte, error)     // Returns signature or error
	Alg() string                                            // returns the alg identifier for this method (example: 'HS256')
}

// RegisterSigningMethod registers the "alg" name and a factory function for signing method.
// This is typically done during init() in the method's implementation
func RegisterSigningMethod(alg string, f func() SigningMethod) {
	signingMethodLock.Lock()
	defer signingMethodLock.Unlock()

	signingMethods[alg] = f
}

// GetSigningMethod retrieves a signing method from an "alg" string
func GetSigningMethod(alg string) (method SigningMethod) {
	signingMethodLock.RLock()
	defer signingMethodLock.RUnlock()

	if methodF, ok := signingMethods[alg]; ok {
		method = methodF()
	}
	return
}

// GetAlgorithms returns a list of registered "alg" names
func GetAlgorithms() (algs []string) {
	signingMethodLock.RLock()
	defer signingMethodLock.RUnlock()

	for alg := range signingMethods {
		algs = append(algs, alg)
	}
	return
}


================================================
FILE: staticcheck.conf
================================================
checks = ["all", "-ST1000", "-ST1003", "-ST1016", "-ST1023"]


================================================
FILE: test/ec256-private.pem
================================================
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIAh5qA3rmqQQuu0vbKV/+zouz/y/Iy2pLpIcWUSyImSwoAoGCCqGSM49
AwEHoUQDQgAEYD54V/vp+54P9DXarYqx4MPcm+HKRIQzNasYSoRQHQ/6S6Ps8tpM
cT+KvIIC8W/e9k0W7Cm72M1P9jU7SLf/vg==
-----END EC PRIVATE KEY-----


================================================
FILE: test/ec256-public.pem
================================================
-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEYD54V/vp+54P9DXarYqx4MPcm+HK
RIQzNasYSoRQHQ/6S6Ps8tpMcT+KvIIC8W/e9k0W7Cm72M1P9jU7SLf/vg==
-----END PUBLIC KEY-----


================================================
FILE: test/ec384-private.pem
================================================
-----BEGIN EC PRIVATE KEY-----
MIGkAgEBBDCaCvMHKhcG/qT7xsNLYnDT7sE/D+TtWIol1ROdaK1a564vx5pHbsRy
SEKcIxISi1igBwYFK4EEACKhZANiAATYa7rJaU7feLMqrAx6adZFNQOpaUH/Uylb
ZLriOLON5YFVwtVUpO1FfEXZUIQpptRPtc5ixIPY658yhBSb6irfIJUSP9aYTflJ
GKk/mDkK4t8mWBzhiD5B6jg9cEGhGgA=
-----END EC PRIVATE KEY-----


================================================
FILE: test/ec384-public.pem
================================================
-----BEGIN PUBLIC KEY-----
MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE2Gu6yWlO33izKqwMemnWRTUDqWlB/1Mp
W2S64jizjeWBVcLVVKTtRXxF2VCEKabUT7XOYsSD2OufMoQUm+oq3yCVEj/WmE35
SRipP5g5CuLfJlgc4Yg+Qeo4PXBBoRoA
-----END PUBLIC KEY-----


================================================
FILE: test/ec512-private.pem
================================================
-----BEGIN EC PRIVATE KEY-----
MIHcAgEBBEIB0pE4uFaWRx7t03BsYlYvF1YvKaBGyvoakxnodm9ou0R9wC+sJAjH
QZZJikOg4SwNqgQ/hyrOuDK2oAVHhgVGcYmgBwYFK4EEACOhgYkDgYYABAAJXIuw
12MUzpHggia9POBFYXSxaOGKGbMjIyDI+6q7wi7LMw3HgbaOmgIqFG72o8JBQwYN
4IbXHf+f86CRY1AA2wHzbHvt6IhkCXTNxBEffa1yMUgu8n9cKKF2iLgyQKcKqW33
8fGOw/n3Rm2Yd/EB56u2rnD29qS+nOM9eGS+gy39OQ==
-----END EC PRIVATE KEY-----


================================================
FILE: test/ec512-public.pem
================================================
-----BEGIN PUBLIC KEY-----
MIGbMBAGByqGSM49AgEGBSuBBAAjA4GGAAQACVyLsNdjFM6R4IImvTzgRWF0sWjh
ihmzIyMgyPuqu8IuyzMNx4G2jpoCKhRu9qPCQUMGDeCG1x3/n/OgkWNQANsB82x7
7eiIZAl0zcQRH32tcjFILvJ/XCihdoi4MkCnCqlt9/HxjsP590ZtmHfxAeertq5w
9vakvpzjPXhkvoMt/Tk=
-----END PUBLIC KEY-----


================================================
FILE: test/ed25519-private.pem
================================================
-----BEGIN PRIVATE KEY-----
MC4CAQAwBQYDK2VwBCIEIEFMEZrmlYxczXKFxIlNvNGR5JQvDhTkLovJYxwQd3ua
-----END PRIVATE KEY-----


================================================
FILE: test/ed25519-public.pem
================================================
-----BEGIN PUBLIC KEY-----
MCowBQYDK2VwAyEAWH7z6hpYqvPns2i4n9yymwvB3APhi4LyQ7iHOT6crtE=
-----END PUBLIC KEY-----


================================================
FILE: test/examplePaddedKey-public.pem
================================================
-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEIcaUjXhC7Mn2OonyfHF+zjblKkns
4GLbILnHrZr+aQwddiff5urCDAZ177t81Mn39CDs3uhlNDxfRIRheGnK/Q==
-----END PUBLIC KEY-----

=============================================
Download .txt
gitextract_upwvedr3/

├── .github/
│   ├── CODEOWNERS
│   ├── dependabot.yml
│   ├── release.yml
│   ├── spell-check.toml
│   └── workflows/
│       ├── build.yml
│       ├── codeql-analysis.yml
│       ├── lint.yml
│       └── spell-check.yml
├── .gitignore
├── LICENSE
├── MIGRATION_GUIDE.md
├── README.md
├── SECURITY.md
├── VERSION_HISTORY.md
├── claims.go
├── cmd/
│   └── jwt/
│       ├── README.md
│       └── main.go
├── doc.go
├── ecdsa.go
├── ecdsa_test.go
├── ecdsa_utils.go
├── ed25519.go
├── ed25519_test.go
├── ed25519_utils.go
├── errors.go
├── errors_test.go
├── example_test.go
├── go.mod
├── go.sum
├── hmac.go
├── hmac_example_test.go
├── hmac_test.go
├── http_example_test.go
├── jwt_test.go
├── map_claims.go
├── map_claims_test.go
├── none.go
├── none_test.go
├── parser.go
├── parser_option.go
├── parser_test.go
├── registered_claims.go
├── request/
│   ├── doc.go
│   ├── extractor.go
│   ├── extractor_example_test.go
│   ├── extractor_test.go
│   ├── oauth2.go
│   ├── request.go
│   └── request_test.go
├── rsa.go
├── rsa_pss.go
├── rsa_pss_test.go
├── rsa_test.go
├── rsa_utils.go
├── signing_method.go
├── staticcheck.conf
├── test/
│   ├── ec256-private.pem
│   ├── ec256-public.pem
│   ├── ec384-private.pem
│   ├── ec384-public.pem
│   ├── ec512-private.pem
│   ├── ec512-public.pem
│   ├── ed25519-private.pem
│   ├── ed25519-public.pem
│   ├── examplePaddedKey-public.pem
│   ├── helpers.go
│   ├── hmacTestKey
│   ├── privateSecure.pem
│   ├── sample_key
│   └── sample_key.pub
├── token.go
├── token_option.go
├── token_test.go
├── types.go
├── types_test.go
├── validator.go
└── validator_test.go
Download .txt
SYMBOL INDEX (250 symbols across 44 files)

FILE: claims.go
  type Claims (line 9) | type Claims interface

FILE: cmd/jwt/main.go
  function main (line 39) | func main() {
  function start (line 63) | func start() error {
  function loadData (line 78) | func loadData(p string) (_ []byte, retErr error) {
  function printJSON (line 103) | func printJSON(j any) error {
  function verifyToken (line 122) | func verifyToken() error {
  function signToken (line 177) | func signToken() error {
  function showToken (line 266) | func showToken() error {
  function isEs (line 298) | func isEs() bool {
  function isRs (line 302) | func isRs() bool {
  function isEd (line 306) | func isEd() bool {
  function isNone (line 310) | func isNone() bool {
  function algHelp (line 314) | func algHelp() string {
  type ArgList (line 333) | type ArgList
    method String (line 335) | func (l ArgList) String() string {
    method Set (line 340) | func (l ArgList) Set(arg string) error {

FILE: ecdsa.go
  type SigningMethodECDSA (line 18) | type SigningMethodECDSA struct
    method Alg (line 52) | func (m *SigningMethodECDSA) Alg() string {
    method Verify (line 58) | func (m *SigningMethodECDSA) Verify(signingString string, sig []byte, ...
    method Sign (line 92) | func (m *SigningMethodECDSA) Sign(signingString string, key any) ([]by...
  function init (line 32) | func init() {

FILE: ecdsa_test.go
  function TestECDSAVerify (line 55) | func TestECDSAVerify(t *testing.T) {
  function TestECDSASign (line 79) | func TestECDSASign(t *testing.T) {
  function BenchmarkECDSAParsing (line 111) | func BenchmarkECDSAParsing(b *testing.B) {
  function BenchmarkECDSASigning (line 129) | func BenchmarkECDSASigning(b *testing.B) {
  function decodeSegment (line 168) | func decodeSegment(t interface{ Fatalf(string, ...any) }, signature stri...
  function encodeSegment (line 178) | func encodeSegment(sig []byte) string {

FILE: ecdsa_utils.go
  function ParseECPrivateKeyFromPEM (line 16) | func ParseECPrivateKeyFromPEM(key []byte) (*ecdsa.PrivateKey, error) {
  function ParseECPublicKeyFromPEM (line 43) | func ParseECPublicKeyFromPEM(key []byte) (*ecdsa.PublicKey, error) {

FILE: ed25519.go
  type SigningMethodEd25519 (line 16) | type SigningMethodEd25519 struct
    method Alg (line 30) | func (m *SigningMethodEd25519) Alg() string {
    method Verify (line 36) | func (m *SigningMethodEd25519) Verify(signingString string, sig []byte...
    method Sign (line 58) | func (m *SigningMethodEd25519) Sign(signingString string, key any) ([]...
  function init (line 23) | func init() {

FILE: ed25519_test.go
  function TestEd25519Verify (line 37) | func TestEd25519Verify(t *testing.T) {
  function TestEd25519Sign (line 62) | func TestEd25519Sign(t *testing.T) {

FILE: ed25519_utils.go
  function ParseEdPrivateKeyFromPEM (line 17) | func ParseEdPrivateKeyFromPEM(key []byte) (crypto.PrivateKey, error) {
  function ParseEdPublicKeyFromPEM (line 42) | func ParseEdPublicKeyFromPEM(key []byte) (crypto.PublicKey, error) {

FILE: errors.go
  type joinedError (line 31) | type joinedError struct
    method Error (line 35) | func (je joinedError) Error() string {
    method Unwrap (line 54) | func (je joinedError) Unwrap() []error {
  function joinErrors (line 46) | func joinErrors(errs ...error) error {
  function newError (line 71) | func newError(message string, err error, more ...error) error {

FILE: errors_test.go
  function Test_joinErrors (line 9) | func Test_joinErrors(t *testing.T) {
  function Test_newError (line 44) | func Test_newError(t *testing.T) {

FILE: example_test.go
  function ExampleNewWithClaims_registeredClaims (line 17) | func ExampleNewWithClaims_registeredClaims() {
  function ExampleNewWithClaims_customClaimsType (line 34) | func ExampleNewWithClaims_customClaimsType() {
  function ExampleParseWithClaims_customClaimsType (line 79) | func ExampleParseWithClaims_customClaimsType() {
  function ExampleParseWithClaims_validationOptions (line 103) | func ExampleParseWithClaims_validationOptions() {
  type MyCustomClaims (line 125) | type MyCustomClaims struct
    method Validate (line 135) | func (m MyCustomClaims) Validate() error {
  function ExampleParseWithClaims_customValidation (line 147) | func ExampleParseWithClaims_customValidation() {
  function ExampleParse_errorChecking (line 165) | func ExampleParse_errorChecking() {

FILE: hmac.go
  type SigningMethodHMAC (line 11) | type SigningMethodHMAC struct
    method Alg (line 44) | func (m *SigningMethodHMAC) Alg() string {
    method Verify (line 58) | func (m *SigningMethodHMAC) Verify(signingString string, sig []byte, k...
    method Sign (line 91) | func (m *SigningMethodHMAC) Sign(signingString string, key any) ([]byt...
  function init (line 24) | func init() {

FILE: hmac_example_test.go
  function init (line 17) | func init() {
  function ExampleNewWithClaims_hmac (line 27) | func ExampleNewWithClaims_hmac() {
  function ExampleParse_hmac (line 42) | func ExampleParse_hmac() {

FILE: hmac_test.go
  function TestHMACVerify (line 52) | func TestHMACVerify(t *testing.T) {
  function TestHMACSign (line 67) | func TestHMACSign(t *testing.T) {
  function BenchmarkHS256Signing (line 84) | func BenchmarkHS256Signing(b *testing.B) {
  function BenchmarkHS384Signing (line 88) | func BenchmarkHS384Signing(b *testing.B) {
  function BenchmarkHS512Signing (line 92) | func BenchmarkHS512Signing(b *testing.B) {

FILE: http_example_test.go
  constant privKeyPath (line 24) | privKeyPath = "test/sample_key"
  constant pubKeyPath (line 25) | pubKeyPath  = "test/sample_key.pub"
  function init (line 35) | func init() {
  function fatal (line 62) | func fatal(err error) {
  type CustomerInfo (line 69) | type CustomerInfo struct
  type CustomClaimsExample (line 74) | type CustomClaimsExample struct
  function Example_getTokenViaHTTP (line 80) | func Example_getTokenViaHTTP() {
  function Example_useTokenViaHTTP (line 112) | func Example_useTokenViaHTTP() {
  function createToken (line 135) | func createToken(user string) (string, error) {
  function authHandler (line 155) | func authHandler(w http.ResponseWriter, r *http.Request) {
  function restrictedHandler (line 189) | func restrictedHandler(w http.ResponseWriter, r *http.Request) {

FILE: jwt_test.go
  function TestSplitToken (line 7) | func TestSplitToken(t *testing.T) {

FILE: map_claims.go
  type MapClaims (line 10) | type MapClaims
    method GetExpirationTime (line 13) | func (m MapClaims) GetExpirationTime() (*NumericDate, error) {
    method GetNotBefore (line 18) | func (m MapClaims) GetNotBefore() (*NumericDate, error) {
    method GetIssuedAt (line 23) | func (m MapClaims) GetIssuedAt() (*NumericDate, error) {
    method GetAudience (line 28) | func (m MapClaims) GetAudience() (ClaimStrings, error) {
    method GetIssuer (line 33) | func (m MapClaims) GetIssuer() (string, error) {
    method GetSubject (line 38) | func (m MapClaims) GetSubject() (string, error) {
    method parseNumericDate (line 45) | func (m MapClaims) parseNumericDate(key string) (*NumericDate, error) {
    method parseClaimsString (line 69) | func (m MapClaims) parseClaimsString(key string) (ClaimStrings, error) {
    method parseString (line 92) | func (m MapClaims) parseString(key string) (string, error) {

FILE: map_claims_test.go
  function TestVerifyAud (line 8) | func TestVerifyAud(t *testing.T) {
  function TestMapclaimsVerifyIssuedAtInvalidTypeString (line 80) | func TestMapclaimsVerifyIssuedAtInvalidTypeString(t *testing.T) {
  function TestMapclaimsVerifyNotBeforeInvalidTypeString (line 91) | func TestMapclaimsVerifyNotBeforeInvalidTypeString(t *testing.T) {
  function TestMapclaimsVerifyExpiresAtInvalidTypeString (line 102) | func TestMapclaimsVerifyExpiresAtInvalidTypeString(t *testing.T) {
  function TestMapClaimsVerifyExpiresAtExpire (line 114) | func TestMapClaimsVerifyExpiresAtExpire(t *testing.T) {
  function TestMapClaims_parseString (line 143) | func TestMapClaims_parseString(t *testing.T) {

FILE: none.go
  constant UnsafeAllowNoneSignatureType (line 7) | UnsafeAllowNoneSignatureType unsafeNoneMagicConstant = "none signing met...
  type signingMethodNone (line 11) | type signingMethodNone struct
    method Alg (line 23) | func (m *signingMethodNone) Alg() string {
    method Verify (line 28) | func (m *signingMethodNone) Verify(signingString string, sig []byte, k...
    method Sign (line 44) | func (m *signingMethodNone) Sign(signingString string, key any) ([]byt...
  type unsafeNoneMagicConstant (line 12) | type unsafeNoneMagicConstant
  function init (line 14) | func init() {

FILE: none_test.go
  function TestNoneVerify (line 45) | func TestNoneVerify(t *testing.T) {
  function TestNoneSign (line 60) | func TestNoneSign(t *testing.T) {

FILE: parser.go
  constant tokenDelimiter (line 11) | tokenDelimiter = "."
  type Parser (line 13) | type Parser struct
    method Parse (line 46) | func (p *Parser) Parse(tokenString string, keyFunc Keyfunc) (*Token, e...
    method ParseWithClaims (line 57) | func (p *Parser) ParseWithClaims(tokenString string, claims Claims, ke...
    method ParseUnverified (line 136) | func (p *Parser) ParseUnverified(tokenString string, claims Claims) (t...
    method DecodeSegment (line 234) | func (p *Parser) DecodeSegment(seg string) ([]byte, error) {
  function NewParser (line 31) | func NewParser(options ...ParserOption) *Parser {
  function splitToken (line 207) | func splitToken(token string) ([]string, bool) {
  function Parse (line 257) | func Parse(tokenString string, keyFunc Keyfunc, options ...ParserOption)...
  function ParseWithClaims (line 268) | func ParseWithClaims(tokenString string, claims Claims, keyFunc Keyfunc,...

FILE: parser_option.go
  type ParserOption (line 7) | type ParserOption
  function WithValidMethods (line 13) | func WithValidMethods(methods []string) ParserOption {
  function WithJSONNumber (line 21) | func WithJSONNumber() ParserOption {
  function WithoutClaimsValidation (line 29) | func WithoutClaimsValidation() ParserOption {
  function WithLeeway (line 36) | func WithLeeway(leeway time.Duration) ParserOption {
  function WithTimeFunc (line 45) | func WithTimeFunc(f func() time.Time) ParserOption {
  function WithIssuedAt (line 53) | func WithIssuedAt() ParserOption {
  function WithExpirationRequired (line 61) | func WithExpirationRequired() ParserOption {
  function WithNotBeforeRequired (line 69) | func WithNotBeforeRequired() ParserOption {
  function WithAudience (line 83) | func WithAudience(aud ...string) ParserOption {
  function WithAllAudiences (line 99) | func WithAllAudiences(aud ...string) ParserOption {
  function WithIssuer (line 114) | func WithIssuer(iss string) ParserOption {
  function WithSubject (line 128) | func WithSubject(sub string) ParserOption {
  function WithPaddingAllowed (line 138) | func WithPaddingAllowed() ParserOption {
  function WithStrictDecoding (line 147) | func WithStrictDecoding() ParserOption {

FILE: parser_test.go
  type customClaimsWithDifferentTypes (line 21) | type customClaimsWithDifferentTypes struct
  type CustomObject (line 34) | type CustomObject struct
  function init (line 71) | func init() {
  function signToken (line 499) | func signToken(claims jwt.Claims, signingMethod jwt.SigningMethod) string {
  function TestParser_Parse (line 512) | func TestParser_Parse(t *testing.T) {
  function TestParser_ParseUnverified (line 588) | func TestParser_ParseUnverified(t *testing.T) {
  function TestSetPadding (line 800) | func TestSetPadding(t *testing.T) {
  function BenchmarkParseUnverified (line 836) | func BenchmarkParseUnverified(b *testing.B) {
  function benchmarkParsing (line 864) | func benchmarkParsing(b *testing.B, parser *jwt.Parser, tokenString stri...
  function benchmarkSigning (line 879) | func benchmarkSigning(b *testing.B, method jwt.SigningMethod, key any) {

FILE: registered_claims.go
  type RegisteredClaims (line 12) | type RegisteredClaims struct
    method GetExpirationTime (line 36) | func (c RegisteredClaims) GetExpirationTime() (*NumericDate, error) {
    method GetNotBefore (line 41) | func (c RegisteredClaims) GetNotBefore() (*NumericDate, error) {
    method GetIssuedAt (line 46) | func (c RegisteredClaims) GetIssuedAt() (*NumericDate, error) {
    method GetAudience (line 51) | func (c RegisteredClaims) GetAudience() (ClaimStrings, error) {
    method GetIssuer (line 56) | func (c RegisteredClaims) GetIssuer() (string, error) {
    method GetSubject (line 61) | func (c RegisteredClaims) GetSubject() (string, error) {

FILE: request/extractor.go
  type Extractor (line 17) | type Extractor interface
  type HeaderExtractor (line 23) | type HeaderExtractor
    method ExtractToken (line 25) | func (e HeaderExtractor) ExtractToken(req *http.Request) (string, erro...
  type ArgumentExtractor (line 38) | type ArgumentExtractor
    method ExtractToken (line 40) | func (e ArgumentExtractor) ExtractToken(req *http.Request) (string, er...
  type MultiExtractor (line 55) | type MultiExtractor
    method ExtractToken (line 57) | func (e MultiExtractor) ExtractToken(req *http.Request) (string, error) {
  type PostExtractionFilter (line 71) | type PostExtractionFilter struct
    method ExtractToken (line 76) | func (e *PostExtractionFilter) ExtractToken(req *http.Request) (string...
  type BearerExtractor (line 87) | type BearerExtractor struct
    method ExtractToken (line 89) | func (e BearerExtractor) ExtractToken(req *http.Request) (string, erro...

FILE: request/extractor_example_test.go
  constant exampleTokenA (line 9) | exampleTokenA = "A"
  function ExampleHeaderExtractor (line 12) | func ExampleHeaderExtractor() {
  function ExampleArgumentExtractor (line 23) | func ExampleArgumentExtractor() {

FILE: request/extractor_test.go
  function TestExtractor (line 66) | func TestExtractor(t *testing.T) {
  function makeExampleRequest (line 85) | func makeExampleRequest(method, path string, headers map[string]string, ...
  function TestBearerExtractor (line 93) | func TestBearerExtractor(t *testing.T) {

FILE: request/oauth2.go
  function stripBearerPrefixFromTokenString (line 8) | func stripBearerPrefixFromTokenString(tok string) (string, error) {

FILE: request/request.go
  function ParseFromRequest (line 15) | func ParseFromRequest(req *http.Request, extractor Extractor, keyFunc jw...
  function ParseFromRequestWithClaims (line 45) | func ParseFromRequestWithClaims(req *http.Request, extractor Extractor, ...
  type fromRequestParser (line 49) | type fromRequestParser struct
  type ParseFromRequestOption (line 56) | type ParseFromRequestOption
  function WithClaims (line 59) | func WithClaims(claims jwt.Claims) ParseFromRequestOption {
  function WithParser (line 66) | func WithParser(parser *jwt.Parser) ParseFromRequestOption {

FILE: request/request_test.go
  function TestParseRequest (line 57) | func TestParseRequest(t *testing.T) {

FILE: rsa.go
  type SigningMethodRSA (line 11) | type SigningMethodRSA struct
    method Alg (line 43) | func (m *SigningMethodRSA) Alg() string {
    method Verify (line 49) | func (m *SigningMethodRSA) Verify(signingString string, sig []byte, ke...
    method Sign (line 70) | func (m *SigningMethodRSA) Sign(signingString string, key any) ([]byte...
  function init (line 23) | func init() {

FILE: rsa_pss.go
  type SigningMethodRSAPSS (line 10) | type SigningMethodRSAPSS struct
    method Verify (line 82) | func (m *SigningMethodRSAPSS) Verify(signingString string, sig []byte,...
    method Sign (line 108) | func (m *SigningMethodRSAPSS) Sign(signingString string, key any) ([]b...
  function init (line 27) | func init() {

FILE: rsa_pss_test.go
  function TestRSAPSSVerify (line 51) | func TestRSAPSSVerify(t *testing.T) {
  function TestRSAPSSSign (line 74) | func TestRSAPSSSign(t *testing.T) {
  function TestRSAPSSSaltLengthCompatibility (line 101) | func TestRSAPSSSaltLengthCompatibility(t *testing.T) {
  function makeToken (line 134) | func makeToken(method jwt.SigningMethod) string {
  function verify (line 147) | func verify(t *testing.T, signingMethod jwt.SigningMethod, token string)...

FILE: rsa_test.go
  function TestRSAVerify (line 49) | func TestRSAVerify(t *testing.T) {
  function TestRSASign (line 67) | func TestRSASign(t *testing.T) {
  function TestRSAVerifyWithPreParsedPrivateKey (line 86) | func TestRSAVerifyWithPreParsedPrivateKey(t *testing.T) {
  function TestRSAWithPreParsedPrivateKey (line 100) | func TestRSAWithPreParsedPrivateKey(t *testing.T) {
  function TestRSAKeyParsing (line 117) | func TestRSAKeyParsing(t *testing.T) {
  function BenchmarkRSAParsing (line 173) | func BenchmarkRSAParsing(b *testing.B) {
  function BenchmarkRS256Signing (line 187) | func BenchmarkRS256Signing(b *testing.B) {
  function BenchmarkRS384Signing (line 197) | func BenchmarkRS384Signing(b *testing.B) {
  function BenchmarkRS512Signing (line 207) | func BenchmarkRS512Signing(b *testing.B) {

FILE: rsa_utils.go
  function ParseRSAPrivateKeyFromPEM (line 17) | func ParseRSAPrivateKeyFromPEM(key []byte) (*rsa.PrivateKey, error) {
  function ParseRSAPrivateKeyFromPEMWithPassword (line 47) | func ParseRSAPrivateKeyFromPEMWithPassword(key []byte, password string) ...
  function ParseRSAPublicKeyFromPEM (line 79) | func ParseRSAPublicKeyFromPEM(key []byte) (*rsa.PublicKey, error) {

FILE: signing_method.go
  type SigningMethod (line 14) | type SigningMethod interface
  function RegisterSigningMethod (line 22) | func RegisterSigningMethod(alg string, f func() SigningMethod) {
  function GetSigningMethod (line 30) | func GetSigningMethod(alg string) (method SigningMethod) {
  function GetAlgorithms (line 41) | func GetAlgorithms() (algs []string) {

FILE: test/helpers.go
  function LoadRSAPrivateKeyFromDisk (line 11) | func LoadRSAPrivateKeyFromDisk(location string) *rsa.PrivateKey {
  function LoadRSAPublicKeyFromDisk (line 23) | func LoadRSAPublicKeyFromDisk(location string) *rsa.PublicKey {
  function MakeSampleToken (line 36) | func MakeSampleToken(c jwt.Claims, method jwt.SigningMethod, key any) st...
  function LoadECPrivateKeyFromDisk (line 47) | func LoadECPrivateKeyFromDisk(location string) crypto.PrivateKey {
  function LoadECPublicKeyFromDisk (line 59) | func LoadECPublicKeyFromDisk(location string) crypto.PublicKey {

FILE: token.go
  type Keyfunc (line 16) | type Keyfunc
  type VerificationKey (line 19) | type VerificationKey interface
  type VerificationKeySet (line 24) | type VerificationKeySet struct
  type Token (line 30) | type Token struct
    method SignedString (line 63) | func (t *Token) SignedString(key any) (string, error) {
    method SigningString (line 82) | func (t *Token) SigningString() (string, error) {
    method EncodeSegment (line 100) | func (*Token) EncodeSegment(seg []byte) string {
  function New (line 41) | func New(method SigningMethod, opts ...TokenOption) *Token {
  function NewWithClaims (line 47) | func NewWithClaims(method SigningMethod, claims Claims, opts ...TokenOpt...

FILE: token_option.go
  type TokenOption (line 5) | type TokenOption

FILE: token_test.go
  function TestToken_SigningString (line 9) | func TestToken_SigningString(t1 *testing.T) {
  function BenchmarkToken_SigningString (line 62) | func BenchmarkToken_SigningString(b *testing.B) {

FILE: types.go
  type NumericDate (line 32) | type NumericDate struct
    method MarshalJSON (line 51) | func (date NumericDate) MarshalJSON() (b []byte, err error) {
    method UnmarshalJSON (line 80) | func (date *NumericDate) UnmarshalJSON(b []byte) (err error) {
  function NewNumericDate (line 38) | func NewNumericDate(t time.Time) *NumericDate {
  function newNumericDateFromSeconds (line 44) | func newNumericDateFromSeconds(f float64) *NumericDate {
  type ClaimStrings (line 103) | type ClaimStrings
    method UnmarshalJSON (line 105) | func (s *ClaimStrings) UnmarshalJSON(data []byte) (err error) {
    method MarshalJSON (line 138) | func (s ClaimStrings) MarshalJSON() (b []byte, err error) {

FILE: types_test.go
  function TestNumericDate (line 15) | func TestNumericDate(t *testing.T) {
  function TestSingleArrayMarshal (line 40) | func TestSingleArrayMarshal(t *testing.T) {
  function TestNumericDate_MarshalJSON (line 70) | func TestNumericDate_MarshalJSON(t *testing.T) {
  function TestGetSignatureAfterSigning (line 131) | func TestGetSignatureAfterSigning(t *testing.T) {

FILE: validator.go
  type ClaimsValidator (line 26) | type ClaimsValidator interface
  type Validator (line 36) | type Validator struct
    method Validate (line 95) | func (v *Validator) Validate(claims Claims) error {
    method verifyExpiresAt (line 175) | func (v *Validator) verifyExpiresAt(claims Claims, cmp time.Time, requ...
    method verifyIssuedAt (line 196) | func (v *Validator) verifyIssuedAt(claims Claims, cmp time.Time, requi...
    method verifyNotBefore (line 217) | func (v *Validator) verifyNotBefore(claims Claims, cmp time.Time, requ...
    method verifyAudience (line 237) | func (v *Validator) verifyAudience(claims Claims, cmp []string, expect...
    method verifyIssuer (line 279) | func (v *Validator) verifyIssuer(claims Claims, cmp string, required b...
    method verifySubject (line 299) | func (v *Validator) verifySubject(claims Claims, cmp string, required ...
  function NewValidator (line 84) | func NewValidator(opts ...ParserOption) *Validator {
  function errorIfFalse (line 314) | func errorIfFalse(value bool, err error) error {
  function errorIfRequired (line 324) | func errorIfRequired(required bool, claim string) error {

FILE: validator_test.go
  type MyCustomClaims (line 11) | type MyCustomClaims struct
    method Validate (line 16) | func (m MyCustomClaims) Validate() error {
  function Test_Validator_Validate (line 23) | func Test_Validator_Validate(t *testing.T) {
  function Test_Validator_verifyExpiresAt (line 91) | func Test_Validator_verifyExpiresAt(t *testing.T) {
  function Test_Validator_verifyIssuer (line 135) | func Test_Validator_verifyIssuer(t *testing.T) {
  function Test_Validator_verifySubject (line 176) | func Test_Validator_verifySubject(t *testing.T) {
  function Test_Validator_verifyIssuedAt (line 217) | func Test_Validator_verifyIssuedAt(t *testing.T) {
  function Test_Validator_requireNotBefore (line 265) | func Test_Validator_requireNotBefore(t *testing.T) {
  function Test_Validator_verifyAudience (line 332) | func Test_Validator_verifyAudience(t *testing.T) {
Condensed preview — 77 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (255K chars).
[
  {
    "path": ".github/CODEOWNERS",
    "chars": 21,
    "preview": "*  @oxisto @mfridman\n"
  },
  {
    "path": ".github/dependabot.yml",
    "chars": 442,
    "preview": "# To get started with Dependabot version updates, you'll need to specify which\n# package ecosystems to update and where "
  },
  {
    "path": ".github/release.yml",
    "chars": 198,
    "preview": "changelog:\n  categories:\n    - title: 🔐 Features\n      labels:\n        - '*'\n      exclude:\n        labels:\n          - "
  },
  {
    "path": ".github/spell-check.toml",
    "chars": 396,
    "preview": "[default]\nextend-ignore-re = [\n    # Ignore JWT/JWE tokens\n    \"\\\\beyJ[\\\\dA-Za-z=_-]+(?:\\\\.[\\\\dA-Za-z=_-]{3,}){1,4}\",\n]\n"
  },
  {
    "path": ".github/workflows/build.yml",
    "chars": 1680,
    "preview": "name: build\n\non:\n  push:\n    branches:\n      - main\n  pull_request:\n    types: [opened, synchronize, reopened]\n\njobs:\n  "
  },
  {
    "path": ".github/workflows/codeql-analysis.yml",
    "chars": 2388,
    "preview": "# For most projects, this workflow file will not need changing; you simply need\n# to commit it to your repository.\n#\n# Y"
  },
  {
    "path": ".github/workflows/lint.yml",
    "chars": 1350,
    "preview": "name: golangci\non:\n  push:\n    branches:\n      - main\n  pull_request:\njobs:\n  golangci:\n    name: lint\n    runs-on: ubun"
  },
  {
    "path": ".github/workflows/spell-check.yml",
    "chars": 458,
    "preview": "name: spelling\n\npermissions:\n  contents: read\n\non:\n  push:\n    branches:\n      - main\n  pull_request:\n\nenv:\n  CLICOLOR: "
  },
  {
    "path": ".gitignore",
    "chars": 22,
    "preview": ".DS_Store\nbin\n.idea/\n\n"
  },
  {
    "path": "LICENSE",
    "chars": 1100,
    "preview": "Copyright (c) 2012 Dave Grijalva\nCopyright (c) 2021 golang-jwt maintainers\n\nPermission is hereby granted, free of charge"
  },
  {
    "path": "MIGRATION_GUIDE.md",
    "chars": 8684,
    "preview": "# Migration Guide (v5.0.0)\n\nVersion `v5` contains a major rework of core functionalities in the `jwt-go`\nlibrary. This i"
  },
  {
    "path": "README.md",
    "chars": 8030,
    "preview": "# jwt-go\n\n[![build](https://github.com/golang-jwt/jwt/actions/workflows/build.yml/badge.svg)](https://github.com/golang-"
  },
  {
    "path": "SECURITY.md",
    "chars": 904,
    "preview": "# Security Policy\n\n## Supported Versions\n\nAs of November 2024 (and until this document is updated), the latest version `"
  },
  {
    "path": "VERSION_HISTORY.md",
    "chars": 8015,
    "preview": "# `jwt-go` Version History\n\nThe following version history is kept for historic purposes. To retrieve the current changes"
  },
  {
    "path": "claims.go",
    "chars": 638,
    "preview": "package jwt\n\n// Claims represent any form of a JWT Claims Set according to\n// https://datatracker.ietf.org/doc/html/rfc7"
  },
  {
    "path": "cmd/jwt/README.md",
    "chars": 624,
    "preview": "`jwt` command-line tool\n=======================\n\nThis is a simple tool to sign, verify and show JSON Web Tokens from\nthe"
  },
  {
    "path": "cmd/jwt/main.go",
    "chars": 8286,
    "preview": "// A useful example app.  You can use this to debug your tokens on the command line.\n// This is also a great place to lo"
  },
  {
    "path": "doc.go",
    "chars": 166,
    "preview": "// Package jwt is a Go implementation of JSON Web Tokens: http://self-issued.info/docs/draft-jones-json-web-token.html\n/"
  },
  {
    "path": "ecdsa.go",
    "chars": 3463,
    "preview": "package jwt\n\nimport (\n\t\"crypto\"\n\t\"crypto/ecdsa\"\n\t\"crypto/rand\"\n\t\"errors\"\n\t\"math/big\"\n)\n\nvar (\n\t// Sadly this is missing "
  },
  {
    "path": "ecdsa_test.go",
    "chars": 5116,
    "preview": "package jwt_test\n\nimport (\n\t\"crypto/ecdsa\"\n\t\"os\"\n\t\"reflect\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/golang-jwt/jwt/v5\"\n)\n\nva"
  },
  {
    "path": "ecdsa_utils.go",
    "chars": 1580,
    "preview": "package jwt\n\nimport (\n\t\"crypto/ecdsa\"\n\t\"crypto/x509\"\n\t\"encoding/pem\"\n\t\"errors\"\n)\n\nvar (\n\tErrNotECPublicKey  = errors.New"
  },
  {
    "path": "ed25519.go",
    "chars": 2074,
    "preview": "package jwt\n\nimport (\n\t\"crypto\"\n\t\"crypto/ed25519\"\n\t\"crypto/rand\"\n\t\"errors\"\n)\n\nvar (\n\tErrEd25519Verification = errors.New"
  },
  {
    "path": "ed25519_test.go",
    "chars": 2281,
    "preview": "package jwt_test\n\nimport (\n\t\"os\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/golang-jwt/jwt/v5\"\n)\n\nvar ed25519TestData = []struc"
  },
  {
    "path": "ed25519_utils.go",
    "chars": 1398,
    "preview": "package jwt\n\nimport (\n\t\"crypto\"\n\t\"crypto/ed25519\"\n\t\"crypto/x509\"\n\t\"encoding/pem\"\n\t\"errors\"\n)\n\nvar (\n\tErrNotEdPrivateKey "
  },
  {
    "path": "errors.go",
    "chars": 2896,
    "preview": "package jwt\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"strings\"\n)\n\nvar (\n\tErrInvalidKey                = errors.New(\"key is invalid\")\n"
  },
  {
    "path": "errors_test.go",
    "chars": 2662,
    "preview": "package jwt\n\nimport (\n\t\"errors\"\n\t\"io\"\n\t\"testing\"\n)\n\nfunc Test_joinErrors(t *testing.T) {\n\ttype args struct {\n\t\terrs []er"
  },
  {
    "path": "example_test.go",
    "chars": 6377,
    "preview": "package jwt_test\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"log\"\n\t\"time\"\n\n\t\"github.com/golang-jwt/jwt/v5\"\n)\n\n// Example (atypical) usi"
  },
  {
    "path": "go.mod",
    "chars": 45,
    "preview": "module github.com/golang-jwt/jwt/v5\n\ngo 1.21\n"
  },
  {
    "path": "go.sum",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "hmac.go",
    "chars": 3411,
    "preview": "package jwt\n\nimport (\n\t\"crypto\"\n\t\"crypto/hmac\"\n\t\"errors\"\n)\n\n// SigningMethodHMAC implements the HMAC-SHA family of signi"
  },
  {
    "path": "hmac_example_test.go",
    "chars": 2240,
    "preview": "package jwt_test\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n\t\"time\"\n\n\t\"github.com/golang-jwt/jwt/v5\"\n)\n\n// For HMAC signing method, t"
  },
  {
    "path": "hmac_test.go",
    "chars": 2986,
    "preview": "package jwt_test\n\nimport (\n\t\"os\"\n\t\"reflect\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/golang-jwt/jwt/v5\"\n)\n\nvar hmacTestData ="
  },
  {
    "path": "http_example_test.go",
    "chars": 5216,
    "preview": "package jwt_test\n\n// Example HTTP auth using asymmetric crypto/RSA keys\n// This is based on a (now outdated) example at "
  },
  {
    "path": "jwt_test.go",
    "chars": 1900,
    "preview": "package jwt\n\nimport (\n\t\"testing\"\n)\n\nfunc TestSplitToken(t *testing.T) {\n\tt.Parallel()\n\n\ttests := []struct {\n\t\tname     s"
  },
  {
    "path": "map_claims.go",
    "chars": 2683,
    "preview": "package jwt\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n)\n\n// MapClaims is a claims type that uses the map[string]any for JSON\n// "
  },
  {
    "path": "map_claims_test.go",
    "chars": 7714,
    "preview": "package jwt\n\nimport (\n\t\"testing\"\n\t\"time\"\n)\n\nfunc TestVerifyAud(t *testing.T) {\n\tvar nilInterface any\n\tvar nilListInterfa"
  },
  {
    "path": "none.go",
    "chars": 1615,
    "preview": "package jwt\n\n// SigningMethodNone implements the none signing method.  This is required by the spec\n// but you probably "
  },
  {
    "path": "none_test.go",
    "chars": 2048,
    "preview": "package jwt_test\n\nimport (\n\t\"reflect\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/golang-jwt/jwt/v5\"\n)\n\nvar noneTestData = []str"
  },
  {
    "path": "parser.go",
    "chars": 9011,
    "preview": "package jwt\n\nimport (\n\t\"bytes\"\n\t\"encoding/base64\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"strings\"\n)\n\nconst tokenDelimiter = \".\"\n\ntype"
  },
  {
    "path": "parser_option.go",
    "chars": 5333,
    "preview": "package jwt\n\nimport \"time\"\n\n// ParserOption is used to implement functional-style options that modify the\n// behavior of"
  },
  {
    "path": "parser_test.go",
    "chars": 36705,
    "preview": "package jwt_test\n\nimport (\n\t\"crypto\"\n\t\"crypto/rsa\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"reflect\"\n\t\"testing\"\n\t\"time\"\n\n\t\"gi"
  },
  {
    "path": "registered_claims.go",
    "chars": 2321,
    "preview": "package jwt\n\n// RegisteredClaims are a structured version of the JWT Claims Set,\n// restricted to Registered Claim Names"
  },
  {
    "path": "request/doc.go",
    "chars": 247,
    "preview": "// Utility package for extracting JWT tokens from\n// HTTP requests.\n//\n// The main function is ParseFromRequest and it's"
  },
  {
    "path": "request/extractor.go",
    "chars": 3071,
    "preview": "package request\n\nimport (\n\t\"errors\"\n\t\"net/http\"\n\t\"strings\"\n)\n\n// Errors\nvar (\n\tErrNoTokenInRequest = errors.New(\"no toke"
  },
  {
    "path": "request/extractor_example_test.go",
    "chars": 635,
    "preview": "package request\n\nimport (\n\t\"fmt\"\n\t\"net/url\"\n)\n\nconst (\n\texampleTokenA = \"A\"\n)\n\nfunc ExampleHeaderExtractor() {\n\treq := m"
  },
  {
    "path": "request/extractor_test.go",
    "chars": 3145,
    "preview": "package request\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"testing\"\n)\n\nvar extractorTestTokenA = \"A\"\nvar extractorTestTok"
  },
  {
    "path": "request/oauth2.go",
    "chars": 821,
    "preview": "package request\n\nimport (\n\t\"strings\"\n)\n\n// Strips 'Bearer ' prefix from bearer token string\nfunc stripBearerPrefixFromTo"
  },
  {
    "path": "request/request.go",
    "chars": 1943,
    "preview": "package request\n\nimport (\n\t\"net/http\"\n\n\t\"github.com/golang-jwt/jwt/v5\"\n)\n\n// ParseFromRequest extracts and parses a JWT "
  },
  {
    "path": "request/request_test.go",
    "chars": 2450,
    "preview": "package request\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"reflect\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/golang-jwt/jwt/v5"
  },
  {
    "path": "rsa.go",
    "chars": 2401,
    "preview": "package jwt\n\nimport (\n\t\"crypto\"\n\t\"crypto/rand\"\n\t\"crypto/rsa\"\n)\n\n// SigningMethodRSA implements the RSA family of signing"
  },
  {
    "path": "rsa_pss.go",
    "chars": 3411,
    "preview": "package jwt\n\nimport (\n\t\"crypto\"\n\t\"crypto/rand\"\n\t\"crypto/rsa\"\n)\n\n// SigningMethodRSAPSS implements the RSAPSS family of s"
  },
  {
    "path": "rsa_pss_test.go",
    "chars": 5674,
    "preview": "package jwt_test\n\nimport (\n\t\"crypto/rsa\"\n\t\"os\"\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/golang-jwt/jwt/v5\"\n\t\"github.c"
  },
  {
    "path": "rsa_test.go",
    "chars": 7183,
    "preview": "package jwt_test\n\nimport (\n\t\"bytes\"\n\t\"crypto/rand\"\n\t\"crypto/rsa\"\n\t\"crypto/x509\"\n\t\"encoding/pem\"\n\t\"os\"\n\t\"reflect\"\n\t\"strin"
  },
  {
    "path": "rsa_utils.go",
    "chars": 2916,
    "preview": "package jwt\n\nimport (\n\t\"crypto/rsa\"\n\t\"crypto/x509\"\n\t\"encoding/pem\"\n\t\"errors\"\n)\n\nvar (\n\tErrKeyMustBePEMEncoded = errors.N"
  },
  {
    "path": "signing_method.go",
    "chars": 1539,
    "preview": "package jwt\n\nimport (\n\t\"sync\"\n)\n\nvar signingMethods = map[string]func() SigningMethod{}\nvar signingMethodLock = new(sync"
  },
  {
    "path": "staticcheck.conf",
    "chars": 61,
    "preview": "checks = [\"all\", \"-ST1000\", \"-ST1003\", \"-ST1016\", \"-ST1023\"]\n"
  },
  {
    "path": "test/ec256-private.pem",
    "chars": 227,
    "preview": "-----BEGIN EC PRIVATE KEY-----\nMHcCAQEEIAh5qA3rmqQQuu0vbKV/+zouz/y/Iy2pLpIcWUSyImSwoAoGCCqGSM49\nAwEHoUQDQgAEYD54V/vp+54P"
  },
  {
    "path": "test/ec256-public.pem",
    "chars": 178,
    "preview": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEYD54V/vp+54P9DXarYqx4MPcm+HK\nRIQzNasYSoRQHQ/6S6Ps8tpMcT+K"
  },
  {
    "path": "test/ec384-private.pem",
    "chars": 288,
    "preview": "-----BEGIN EC PRIVATE KEY-----\nMIGkAgEBBDCaCvMHKhcG/qT7xsNLYnDT7sE/D+TtWIol1ROdaK1a564vx5pHbsRy\nSEKcIxISi1igBwYFK4EEACKh"
  },
  {
    "path": "test/ec384-public.pem",
    "chars": 215,
    "preview": "-----BEGIN PUBLIC KEY-----\nMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE2Gu6yWlO33izKqwMemnWRTUDqWlB/1Mp\nW2S64jizjeWBVcLVVKTtRXxF2VCE"
  },
  {
    "path": "test/ec512-private.pem",
    "chars": 365,
    "preview": "-----BEGIN EC PRIVATE KEY-----\nMIHcAgEBBEIB0pE4uFaWRx7t03BsYlYvF1YvKaBGyvoakxnodm9ou0R9wC+sJAjH\nQZZJikOg4SwNqgQ/hyrOuDK2"
  },
  {
    "path": "test/ec512-public.pem",
    "chars": 268,
    "preview": "-----BEGIN PUBLIC KEY-----\nMIGbMBAGByqGSM49AgEGBSuBBAAjA4GGAAQACVyLsNdjFM6R4IImvTzgRWF0sWjh\nihmzIyMgyPuqu8IuyzMNx4G2jpoC"
  },
  {
    "path": "test/ed25519-private.pem",
    "chars": 119,
    "preview": "-----BEGIN PRIVATE KEY-----\nMC4CAQAwBQYDK2VwBCIEIEFMEZrmlYxczXKFxIlNvNGR5JQvDhTkLovJYxwQd3ua\n-----END PRIVATE KEY-----\n"
  },
  {
    "path": "test/ed25519-public.pem",
    "chars": 113,
    "preview": "-----BEGIN PUBLIC KEY-----\nMCowBQYDK2VwAyEAWH7z6hpYqvPns2i4n9yymwvB3APhi4LyQ7iHOT6crtE=\n-----END PUBLIC KEY-----\n"
  },
  {
    "path": "test/examplePaddedKey-public.pem",
    "chars": 177,
    "preview": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEIcaUjXhC7Mn2OonyfHF+zjblKkns\n4GLbILnHrZr+aQwddiff5urCDAZ1"
  },
  {
    "path": "test/helpers.go",
    "chars": 1371,
    "preview": "package test\n\nimport (\n\t\"crypto\"\n\t\"crypto/rsa\"\n\t\"os\"\n\n\t\"github.com/golang-jwt/jwt/v5\"\n)\n\nfunc LoadRSAPrivateKeyFromDisk("
  },
  {
    "path": "test/hmacTestKey",
    "chars": 37,
    "preview": "\u0003#5K+\u000f~\u0006ew{Z(T(\u000fP.Z\u0006Gwb=\"=.!r\u0005.O\b͚gЀ"
  },
  {
    "path": "test/privateSecure.pem",
    "chars": 1743,
    "preview": "-----BEGIN RSA PRIVATE KEY-----\nProc-Type: 4,ENCRYPTED\nDEK-Info: DES-EDE3-CBC,7487BB8910A3741B\n\niL7m48mbFSIy1Y5xbXWwPTR0"
  },
  {
    "path": "test/sample_key",
    "chars": 1675,
    "preview": "-----BEGIN RSA PRIVATE KEY-----\nMIIEowIBAAKCAQEA4f5wg5l2hKsTeNem/V41fGnJm6gOdrj8ym3rFkEU/wT8RDtn\nSgFEZOQpHEgQ7JL38xUfU0Y"
  },
  {
    "path": "test/sample_key.pub",
    "chars": 451,
    "preview": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4f5wg5l2hKsTeNem/V41\nfGnJm6gOdrj8ym3rFkEU/wT8RDtn"
  },
  {
    "path": "token.go",
    "chars": 3564,
    "preview": "package jwt\n\nimport (\n\t\"crypto\"\n\t\"encoding/base64\"\n\t\"encoding/json\"\n)\n\n// Keyfunc will be used by the Parse methods as a"
  },
  {
    "path": "token_option.go",
    "chars": 185,
    "preview": "package jwt\n\n// TokenOption is a reserved type, which provides some forward compatibility,\n// if we ever want to introdu"
  },
  {
    "path": "token_test.go",
    "chars": 1640,
    "preview": "package jwt_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/golang-jwt/jwt/v5\"\n)\n\nfunc TestToken_SigningString(t1 *testing.T) {\n"
  },
  {
    "path": "types.go",
    "chars": 4879,
    "preview": "package jwt\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"math\"\n\t\"strconv\"\n\t\"time\"\n)\n\n// TimePrecision sets the precision of times"
  },
  {
    "path": "types_test.go",
    "chars": 4551,
    "preview": "package jwt_test\n\nimport (\n\t\"bytes\"\n\t\"encoding/base64\"\n\t\"encoding/json\"\n\t\"math\"\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github."
  },
  {
    "path": "validator.go",
    "chars": 10277,
    "preview": "package jwt\n\nimport (\n\t\"fmt\"\n\t\"slices\"\n\t\"time\"\n)\n\n// ClaimsValidator is an interface that can be implemented by custom c"
  },
  {
    "path": "validator_test.go",
    "chars": 11128,
    "preview": "package jwt\n\nimport (\n\t\"errors\"\n\t\"testing\"\n\t\"time\"\n)\n\nvar ErrFooBar = errors.New(\"must be foobar\")\n\ntype MyCustomClaims "
  }
]

About this extraction

This page contains the full source code of the golang-jwt/jwt GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 77 files (228.0 KB), approximately 74.4k tokens, and a symbol index with 250 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!