func UnverifiedNetworkIdentifier(token string) (ttnpb.PacketBrokerNetworkIdentifier, error) {
	parsed, err := jwt.ParseSigned(token)
	if err != nil {
		return ttnpb.PacketBrokerNetworkIdentifier{}, errOAuth2Token.WithCause(err)
	}
	var claims TokenClaims
	if err := parsed.UnsafeClaimsWithoutVerification(&claims); err != nil {
		return ttnpb.PacketBrokerNetworkIdentifier{}, errOAuth2Token.WithCause(err)
	}
	if len(claims.PacketBroker.Networks) == 0 {
		return ttnpb.PacketBrokerNetworkIdentifier{}, errOAuth2Token.New()
	}
	return ttnpb.PacketBrokerNetworkIdentifier{
		NetId:    claims.PacketBroker.Networks[0].NetID,
		TenantId: claims.PacketBroker.Networks[0].TenantID,
	}, nil
}
UnverifiedNetworkIdentifier returns the Packet Broker network identifier from the given token.
This function does not verify the token.
package packetbroker
import (
	"context"
	"encoding/json"
	"io/ioutil"
	"net"
	"net/http"
	"net/url"
	"strings"
	"sync"
	"time"
	"go.thethings.network/lorawan-stack/v3/pkg/errors"
	"go.thethings.network/lorawan-stack/v3/pkg/ttnpb"
	"golang.org/x/oauth2"
	"golang.org/x/oauth2/clientcredentials"
	"gopkg.in/square/go-jose.v2"
	"gopkg.in/square/go-jose.v2/jwt"
)
type Scope string
const (
	ScopeNetworks Scope = "networks"
)
type tokenOptions struct {
	tokenURL string
	scopes   []Scope
	audience []string
}
type TokenOption func(o *tokenOptions)
func WithTokenURL(tokenURL string) TokenOption {
	return func(o *tokenOptions) {
		o.tokenURL = tokenURL
	}
}
func WithScope(scopes ...Scope) TokenOption {
	return func(o *tokenOptions) {
		o.scopes = append(o.scopes, scopes...)
	}
}
func WithAudienceFromAddresses(addresses ...string) TokenOption {
	return func(o *tokenOptions) {
		hosts := make(map[string]bool, len(addresses))
		for _, addr := range addresses {
			if addr == "" {
				continue
			}
			if h, _, err := net.SplitHostPort(addr); err == nil {
				addr = h
			}
			hosts[addr] = true
		}
		for h := range hosts {
			o.audience = append(o.audience, h)
		}
	}
}
func TokenSource(ctx context.Context, clientID, clientSecret string, opts ...TokenOption) oauth2.TokenSource {
	o := tokenOptions{
		tokenURL: DefaultTokenURL,
	}
	for _, opt := range opts {
		opt(&o)
	}
	scopes := make([]string, len(o.scopes))
	for i, s := range o.scopes {
		scopes[i] = string(s)
	}
	config := clientcredentials.Config{
		ClientID:     clientID,
		ClientSecret: clientSecret,
		Scopes:       scopes,
		AuthStyle:    oauth2.AuthStyleInParams,
		TokenURL:     o.tokenURL,
	}
	if len(o.audience) > 0 {
		config.EndpointParams = url.Values{
			"audience": []string{strings.Join(o.audience, " ")},
		}
	}
	return config.TokenSource(ctx)
}
type TokenNetworkClaim struct {
	NetID    uint32 `json:"nid"`
	TenantID string `json:"tid"`
}
type IAMTokenClaims struct {
	Cluster  bool                `json:"c,omitempty"`
	Networks []TokenNetworkClaim `json:"ns,omitempty"`
	Rights   []int32             `json:"rights,omitempty"`
}
type TokenClaims struct {
	jwt.Claims
	PacketBroker IAMTokenClaims `json:"https://iam.packetbroker.net/claims,omitempty"`
}
var (
	errOAuth2Token   = errors.DefineUnauthenticated("oauth2_token", "invalid OAuth 2.0 token")
	errNotAuthorized = errors.DefinePermissionDenied("not_authorized", "not authorized")
)