Skip to content

Commit

Permalink
Merge pull request #29 from napptive/feature/PG-1247_unverified_parsing
Browse files Browse the repository at this point in the history
PG-1247 add methods to parse unverified tokens
  • Loading branch information
dhiguero authored May 8, 2023
2 parents 184cc24 + 9c51b91 commit f2fe9ed
Show file tree
Hide file tree
Showing 6 changed files with 98 additions and 14 deletions.
12 changes: 9 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
# NJWT

JWT library for the Napptive projects

The purpose of this project is to provide a simple JWT library to handle the authentication tokens of the Napptive platform.

## Usage

To create new tokens:

```go
pc := NewAuthxClaim("userID", "username")
claim := NewClaim("tt", time.Hour, pc)
Expand All @@ -15,9 +18,12 @@ The purpose of this project is to provide a simple JWT library to handle the aut
recoveredClaim, err := tokenMgr.Recover(*token, secret, &AuthxClaim{})
recoveredPC, ok := recClaim.PersonalClaim.(*AuthxClaim)
```

#### JWT Interceptor
this interceptor validates a JWT token received
```

To create an interceptor that validates incoming gRPC calls with a JWT on an authorization header in the context:

```go
cfg := config.JWTConfig{
Secret: "mysecret",
Header: "authorization",
Expand All @@ -33,7 +39,7 @@ s = grpc.NewServer(interceptor.WithServerJWTInterceptor(config))

## License

Copyright 2020 Napptive
Copyright 2023 Napptive

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
Expand Down
14 changes: 7 additions & 7 deletions pkg/config/jwt_config.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@

/**
* Copyright 2020 Napptive
* Copyright 2023 Napptive
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -18,12 +17,13 @@
package config

import (
"strings"

"github.com/napptive/nerrors/pkg/nerrors"
"github.com/rs/zerolog/log"
"strings"
)

// JWT with the JWT configuration
// JWTConfig with the JWT configuration
type JWTConfig struct {
// Secret with the token secret, used to recover the token
Secret string
Expand All @@ -32,15 +32,15 @@ type JWTConfig struct {
}

// NewJWTConfig creates a config object with a given secret and header.
func NewJWTConfig (secret string, header string) JWTConfig {
func NewJWTConfig(secret string, header string) JWTConfig {
return JWTConfig{
Secret: secret,
Header: header,
}
}

// IsValid checks if the configuration options are valid.
func (jc JWTConfig) IsValid () error {
func (jc JWTConfig) IsValid() error {
if jc.Secret == "" {
return nerrors.NewInvalidArgumentError("secret must be filled")
}
Expand All @@ -51,7 +51,7 @@ func (jc JWTConfig) IsValid () error {
}

// Print the configuration using the application logger.
func (jc JWTConfig) Print () {
func (jc JWTConfig) Print() {
log.Info().Str("header", jc.Header).
Str("secret", strings.Repeat("*", len(jc.Secret))).Msg("Authorization")
}
8 changes: 8 additions & 0 deletions pkg/njwt/claims.go
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,14 @@ type ExtendedAuthxClaim struct {
AuthxClaim
}

// ToClaim transforms an ExtendedAuthxClaim into a standard Claim.
func (eac *ExtendedAuthxClaim) ToClaim() *Claim {
return &Claim{
StandardClaims: eac.StandardClaims,
PersonalClaim: eac.AuthxClaim,
}
}

// RefreshClaim is the information stored to create the refresh token.
type RefreshClaim struct {
UserID string
Expand Down
20 changes: 20 additions & 0 deletions pkg/njwt/doc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/**
* Copyright 2023 Napptive
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

// Package njwt provides access to a set of structures and methods related to the creation, validation, and
// inspection of JWT.
package njwt

36 changes: 32 additions & 4 deletions pkg/njwt/token.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/**
* Copyright 2020 Napptive
* Copyright 2023 Napptive
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -18,11 +18,13 @@ package njwt

import (
"fmt"

"github.com/golang-jwt/jwt"
"github.com/rs/xid"
"github.com/rs/zerolog/log"
)

// generateUUID generates a new UUID.
func generateUUID() string {
return xid.New().String()
}
Expand All @@ -31,9 +33,18 @@ func generateUUID() string {
type TokenManager interface {
// Generate a new token with a claim.
Generate(claim *Claim, secret string) (*string, error)
// Recover the claim from a token, if you want to recover the personal claim yo must include the appropiated object.
// Example: recoveredClaim, err := tokenMgr.Recover(*token, secret, &AuthxClaim{})
// Recover the claim from a token, if you want to recover the personal claim you must include the appropriate object.
// Example:
// recoveredClaim, err := tokenMgr.Recover(*token, secret, &AuthxClaim{})
Recover(tk string, secret string, pc interface{}) (*Claim, error)
// RecoverUnverified parses the token returning the parsed claim.
// NOTICE: This method does not verify the authenticity of the token as no secret is used to check it.
// This method is intended to be used by clients that need to check data from a token provided by the library
// without the capability of checking its validity.
// Example:
// personalClaim := &AuthxClaim{}
// unverifiedClaim, err := tokenMgr.RecoverUnverified(*token, personalClaim)
RecoverUnverified(tk string, pc interface{}) (*Claim, error)
}

// New create a new instance of the token generator.
Expand All @@ -54,7 +65,8 @@ func (*manager) Generate(claim *Claim, secret string) (*string, error) {
}

// Recover the claim from a token, if you want to recover the personal claim yo must include the appropiated object.
// Example: recoveredClaim, err := tokenMgr.Recover(*token, secret, &AuthxClaim{})
// Example:
// recoveredClaim, err := tokenMgr.Recover(*token, secret, &AuthxClaim{})
func (*manager) Recover(tk string, secret string, pc interface{}) (*Claim, error) {
claim := &Claim{PersonalClaim: pc}
_, err := jwt.ParseWithClaims(tk, claim, func(token *jwt.Token) (interface{}, error) {
Expand All @@ -73,3 +85,19 @@ func (*manager) Recover(tk string, secret string, pc interface{}) (*Claim, error
}
return claim, nil
}

// RecoverUnverified parses the token returning the parsed claim.
// NOTICE: This method does not verify the authenticity of the token as no secret is used to check it.
// This method is intended to be used by clients that need to check data from a token provided by the library
// without the capability of checking its validity.
// Example:
// personalClaim := &AuthxClaim{}
// unverifiedClaim, err := tokenMgr.RecoverUnverified(*token, personalClaim)
func (*manager) RecoverUnverified(tk string, pc interface{}) (*Claim, error) {
claim := &Claim{PersonalClaim: pc}
_, _, err := new(jwt.Parser).ParseUnverified(tk, claim)
if err != nil {
return nil, err
}
return claim, nil
}
22 changes: 22 additions & 0 deletions pkg/njwt/token_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,4 +91,26 @@ var _ = ginkgo.Describe("NJWT Token Manager tests", func() {

})
})
ginkgo.Context("working with unverified tokens", func() {
tokenMgr := New()
ginkgo.It("should be able to retrieve raw information from a token", func() {
pc := NewAuthxClaim("userID", "username", utils.GetTestAccountId(), utils.GetTestUserName(),
utils.GetTestEnvironmentId(), true, "zoneID", "zoneURL")
claim := NewClaim("tt", time.Hour, pc)

secret := "secret"
token, err := tokenMgr.Generate(claim, secret)
gomega.Expect(err).To(gomega.Succeed())
gomega.Expect(token).NotTo(gomega.BeNil())

personalClaim := &AuthxClaim{}
unverifiedClaim, err := tokenMgr.RecoverUnverified(*token, personalClaim)
gomega.Expect(err).To(gomega.Succeed())
gomega.Expect(unverifiedClaim).ShouldNot(gomega.BeNil())
unverifiedAuthClaim := unverifiedClaim.GetAuthxClaim()
gomega.Expect(unverifiedAuthClaim).ShouldNot(gomega.BeNil())
gomega.Expect(unverifiedAuthClaim).Should(gomega.BeEquivalentTo(pc))
})

})
})

0 comments on commit f2fe9ed

Please sign in to comment.