How to create and verify JWT & PASETO token in Golang
Tags: go, tutorial, webdev, beginners
Published: 2021-04-05 13:02:05

Hello everyone!

In [the previous lecture](https://dev.to/techschoolguru/why-paseto-is-better-than-jwt-for-token-based-authentication-1b0c), we have learned about token based authentication and why PASETO is better than JWT in term of security practice.

Today we will learn how to implement both of them in Golang to see why PASETO is also much easier and simpler to implement compared to JWT.

{% youtube Oi4FHDGILuY %}

Here's:

- Link to the [full series playlist on Youtube](https://bit.ly/backendmaster)
- And its [Github repository](https://github.com/techschool/simplebank)

## Declare token Maker interface

Alright, let’s start!

First, I’m gonna create a new package called `token`. Then create a new file `maker.go` inside this package.

The idea is to declare a general `token.Maker` interface to manage the creation and verification of the tokens. Then later, we will write a `JWTMaker` and a `PasetoMaker` struct that implements this interface. By doing so, we can easily switch between different types of token makers whenever we want.

So this interface will have 2 methods:

```go
type Maker interface {
    CreateToken(username string, duration time.Duration) (string, error)
    VerifyToken(token string) (*Payload, error)
}
```

The `CreateToken()` method takes a `username` string and a valid `duration` as input. It returns a signed token string or an error. Basically, this method will create and sign a new token for a specific username and valid duration.

The second method is `VerifyToken()`, which takes a token string as input, and returns a `Payload` object or an error. We will declare this `Playload` struct in a moment. The role of this `VerifyToken()` method is to checks if the input token is valid or not. If it is valid, the method will return the payload data stored inside the body of the token.

## Declare token Payload struct

OK, now let’s create a new `payload.go` file, and define the `Payload` struct inside it. This struct will contain the payload data of the token.

The most important field is `Username`, which is used to identify the token owner.

Then an `IssuedAt` field to know when the token is created.

When using token based authentication, it’s crucial to make sure that each access token only has a short valid duration. So we need an `ExpiredAt` field to store the time at which the token will be expired.

```go
type Payload struct {
    ID        uuid.UUID `json:"id"`
    Username  string    `json:"username"`
    IssuedAt  time.Time `json:"issued_at"`
    ExpiredAt time.Time `json:"expired_at"`
}
```

Normally these 3 fields should be enough. However, if we want to have a mechanism to invalidate some specific tokens in case they are leaked, we need to add an `ID` field to uniquely identify each token.

Here I use the UUID type for this field. The type is defined in the [google/uuid](https://github.com/google/uuid) package, wo we have to run `go get` command to download and add it to the project.

```bash
go get github.com/google/uuid
```

Next, I’m gonna define a function `NewPayload()` that takes a `username` and a `duration` as input arguments, and returns a `Payload` object or an error. This function will create a new token payload with a specific username and duration.

```go
func NewPayload(username string, duration time.Duration) (*Payload, error) {
    tokenID, err := uuid.NewRandom()
    if err != nil {
        return nil, err
    }

    payload := &Payload{
        ID:        tokenID,
        Username:  username,
        IssuedAt:  time.Now(),
        ExpiredAt: time.Now().Add(duration),
    }
    return payload, nil
}
```

First, we have to call `uuid.NewRandom()` to generate a unique token ID. If an error occurs, we simply return a nil payload and the error itself.

Else, we create the payload, where `ID` is the generated random token `UUID`, `Username` is the input `username`, `IssuedAt` is `time.Now()`, and `ExpiredAt` is `time.Now().Add(duration)`.

Then we just return this payload object and a `nil` error. And we’re done!

## Implement JWT Maker

Now we’re gonna implement a `JWTMaker`. We will need a JWT package for Golang, so let’s open the browser and search for `jwt golang`.

There might be many different packages, but I think this one is the most popular: <https://github.com/dgrijalva/jwt-go>. So let’s copy its URL, and run `go get` in the terminal to install the package:

```bash
go get github.com/dgrijalva/jwt-go
```

OK, the package is installed. Now let’s go back to visual studio code.

I’m gonna create a new file `jwt_maker.go` inside the `token` package. Then declare a new type `JWTMaker` struct. This struct is a JSON web token maker, which implements the `token.Maker` interface.

In this tutorial, I will use symmetric key algorithm to sign the tokens, so this struct will have a field to store the secret key.

```go
type JWTMaker struct {
    secretKey string
}
```

Next, let’s add a function `NewJWTMaker()` that takes a `secretKey` string as input, and returns a `token.Maker` interface, or an `error` as output.

By returning the interface, we will make sure that our `JWTMaker` must implement the `token.Maker` interface. We will see how the go compiler checks this for us in a moment.

Now, although the algorithm we’re gonna use doesn’t require how long the secret key should be, it’s still a good idea to ensure that the key should not be too short, for better security. So I will declare a constant `minSecretKeySize = 32` characters.

```go
const minSecretKeySize = 32

func NewJWTMaker(secretKey string) (Maker, error) {
    if len(secretKey) < minSecretKeySize {
        return nil, fmt.Errorf("invalid key size: must be at least %d characters", minSecretKeySize)
    }
    return &JWTMaker{secretKey}, nil
}
```

Then inside this function, we check if the length of the secret key is less than `minSecretKeySize` or not. If it is, we just return a `nil` object and an error saying that the key must have at least 32 characters.

Otherwise, we return a new `JWTMaker` object with the input `secretKey`, and a `nil` error.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sc909msruhgppcaj8kyl.png)

Now you can see a red line here, because the `JWTMaker` object that we’ve created doesn’t implement the required methods of the `token.Maker` interface, which is the return type of this function.

So in order to fix this, we have to add the `CreateToken()` and `VerifyToken()` methods to this struct.

Let’s copy them from the `token.Maker` interface, and paste them here. Then let’s add the `JWTMaker` receiver in front of each method.

```go
func (maker *JWTMaker) CreateToken(username string, duration time.Duration) (string, error) {}

func (maker *JWTMaker) VerifyToken(token string) (*Payload, error) {}
```

OK, now the red line is gone! Let’s implement the `CreateToken()` method!

### Implement the JWT CreateToken method

First we create a new token payload by calling `NewPayload()`, and pass in the input `username` and valid `duration`.

If error is not nil, we return an empty token string and the error. Else, we create a new `jwtToken` by calling the `jwt.NewWithClaims()` function of the jwt-go package.

This function expects 2 input arguments:

- First, the signing method (or algorithm). I’m gonna use `HS256` in this case.
- Then the claims, which actually is our created payload.

```go
func (maker *JWTMaker) CreateToken(username string, duration time.Duration) (string, error) {
    payload, err := NewPayload(username, duration)
    if err != nil {
        return "", err
    }

    jwtToken := jwt.NewWithClaims(jwt.SigningMethodHS256, payload)
    return jwtToken.SignedString([]byte(maker.secretKey))
}
```

Finally, to generate a token string, we call `jwtToken.SignedString()`, and pass in the `secretKey` after converting it to `[]byte` slice.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gjcnlieurthikp6zzybj.png)

Here we have an error because our `Payload` struct doesn’t implement the `jwt.Claims` interface. It’s missing one method called `Valid()`.

The jwt-go package needs this method to check if the token payload is valid or not. So let’s open the `payload.go` to add this method.

The signature of this method is very simple. It doesn’t take any input argument, and only return an error in case the token is invalid. You can easily find this method in the implementation of the jwt-go package.

```go
var ErrExpiredToken = errors.New("token has expired")

func (payload *Payload) Valid() error {
    if time.Now().After(payload.ExpiredAt) {
        return ErrExpiredToken
    }
    return nil
}
```

The simplest but also the most important thing we must check is the expiration time of the token.

If `time.Now()` is after the `payload.ExpiredAt`, then it means that the token has expired. So we just return a new error saying: token has expired.

We should declare this error as a public constant: `ErrExpiredToken`, so that we can check the error type from outside.

If the token is not expired, then we simply return `nil`. And that’s it! The Valid function is done.

Now back to our `jwt_maker.go` file, we can see that the red line on the payload object is gone.

As we’ve imported the `jwt-go` package, we should run `go mod tidy` in the terminal to add it to the `go.mod` file.

```go
module github.com/techschool/simplebank

go 1.15

require (
    github.com/dgrijalva/jwt-go v3.2.0+incompatible
    github.com/gin-gonic/gin v1.6.3
    github.com/go-playground/validator/v10 v10.4.1
    github.com/golang/mock v1.4.4
    github.com/google/uuid v1.1.4
    github.com/lib/pq v1.9.0
    github.com/o1egl/paseto v1.0.0
    github.com/spf13/viper v1.7.1
    github.com/stretchr/testify v1.6.1
    golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad
)
```

The jwt-go version I’m using is `3.2.0`. In the future, it might be possible that you will use a newer version, such as `4.0`, then the function and interface signatures might be different. However, the idea should be similar.

OK, now the `CreateToken()` method is done. Let’s move on to the `VerifyToken()` method.

### Implement the JWT VerifyToken method

This will be a bit more complicated. First, we have to parse the token by calling `jwt.ParseWithClaims` and pass in the input `token` string, an empty `Payload` object, and a key function.

What is a key function? Well, basically, it’s a function that receives the parsed but unverified token. You should verify its header to make sure that the signing algorithm matches with what you normally use to sign the tokens.

Then if it matches, you return the key so that jwt-go can use it to verify the token. This step is very important to prevent the trivial attack mechanism as I explained in [the previous lecture](https://dev.to/techschoolguru/why-paseto-is-better-than-jwt-for-token-based-authentication-1b0c).

Alright, I’m gonna copy this function signature, and paste it here. Let’s set this input argument’s name to `token`, and its type should be `jwt.Token`. Then we just pass the keyFunc to the `ParseWithClaims()` call.

```go
func (maker *JWTMaker) VerifyToken(token string) (*Payload, error) {
    keyFunc := func(token *jwt.Token) (interface{}, error) {
        _, ok := token.Method.(*jwt.SigningMethodHMAC)
        if !ok {
            return nil, ErrInvalidToken
        }
        return []byte(maker.secretKey), nil
    }

    jwtToken, err := jwt.ParseWithClaims(token, &Payload{}, keyFunc)
    ...
}
```

In the key function, we can get its signing algorithm via the `token.Method` field. Note that its type is a `SigningMethod`, which is just an `interface`. So we have to try converting it to a specific implementation.

In our case, we convert it to `SigningMethodHMAC` because we’re using `HS256`, which is an instance of the `SigningMethodHMAC` struct.

This conversion can be successful or not. If it is not ok, then it means that the algorithm of the token doesn’t match with our signing algorithm, so it’s clearly an invalid token.

We have to return a `nil` key with an `ErrInvalidToken`. I’m gonna declare this new error inside the `payload.go` file, the same place as the `ErrExpiredToken`. They are different types of error that will be returned by our `VerifyToken()` function.

```go
var (
    ErrInvalidToken = errors.New("token is invalid")
    ErrExpiredToken = errors.New("token has expired")
)
```

OK, back to the `JWTMaker`. If the conversion is successful, then it means the algorithm matches. We can just return the secret key that we’re using to sign the token after converting it to `[]byte` slice, and a nil error.

OK now the key function is ready. Let’s continue with the `ParseWithClaims` function call. If it returns a not nil error, then there might be 2 different scenarios: either the token is invalid or it is expired.

But now things get more complicated when we want to differentiate these 2 cases. If we follow the implementation of the jwt-go package, we can see that it automatically calls `token.Claims.Valid()` function under the hood.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/eym96lvfbp57tp2hody0.png)

And in our implementation of this function, we’re returning `ErrExpiredToken` error. However, jwt-go has secretly hiden this original error inside its own `ValidationError` object.

So in order to figure out the real error type, we have to convert the returned error of the `ParseWithClaims()` function to `jwt.ValidationError`

```go
func (maker *JWTMaker) VerifyToken(token string) (*Payload, error) {
    ...

    jwtToken, err := jwt.ParseWithClaims(token, &Payload{}, keyFunc)
    if err != nil {
        verr, ok := err.(*jwt.ValidationError)
        if ok && errors.Is(verr.Inner, ErrExpiredToken) {
            return nil, ErrExpiredToken
        }
        return nil, ErrInvalidToken
    }

    ...
}
```

Here I assign the converted error to the `verr` variable. If the conversion is OK, we use the `errors.Is()` function to check if the `verr.Inner` is actually the `ErrExpiredToken` or not.

If it is, we just return a `nil` payload and the `ErrExpiredToken`. Otherwise, we just return nil and `ErrInvalidToken`.

In case everything is good, and the token is successfully parsed and verified, we will try to get its payload data by converting `jwtToken.Claims` into a Payload object.

```go
func (maker *JWTMaker) VerifyToken(token string) (*Payload, error) {
    keyFunc := func(token *jwt.Token) (interface{}, error) {
        _, ok := token.Method.(*jwt.SigningMethodHMAC)
        if !ok {
            return nil, ErrInvalidToken
        }
        return []byte(maker.secretKey), nil
    }

    jwtToken, err := jwt.ParseWithClaims(token, &Payload{}, keyFunc)
    if err != nil {
        verr, ok := err.(*jwt.ValidationError)
        if ok && errors.Is(verr.Inner, ErrExpiredToken) {
            return nil, ErrExpiredToken
        }
        return nil, ErrInvalidToken
    }

    payload, ok := jwtToken.Claims.(*Payload)
    if !ok {
        return nil, ErrInvalidToken
    }

    return payload, nil
    }

```

If it’s not OK, then we just return `nil` and `ErrInvalidToken`. Else, we return the payload object and a `nil` error.

And that’s it! The `JWTMaker` is completed. Now let’s write some unit test for it!

### Test JWT Maker

I’m gonna create a new file `jwt_maker_test.go` inside the `token` package. Then let’s add a new function `TestJWTMaker()` that takes a `testing.T` object as input.

First, we have to create a new maker by calling the `NewJWTMaker()` function and pass in a random secret key of 32 characters. We require no errors to be returned here.

Next, we generate a `username` with the `util.RandomOwner()` function, and let’s say the token valid `duration` is gonna be `1 minute`.

Let’s also declared 2 variables to compare the result later:

- The `issuedAt` time should be `time.Now()`
- And we add the `duration` to this `issuedAt` time to get the `expiredAt` time of the token.

```go
func TestJWTMaker(t *testing.T) {
    maker, err := NewJWTMaker(util.RandomString(32))
    require.NoError(t, err)

    username := util.RandomOwner()
    duration := time.Minute

    issuedAt := time.Now()
    expiredAt := issuedAt.Add(duration)

    token, err := maker.CreateToken(username, duration)
    require.NoError(t, err)
    require.NotEmpty(t, token)

    payload, err := maker.VerifyToken(token)
    require.NoError(t, err)
    require.NotEmpty(t, token)

    require.NotZero(t, payload.ID)
    require.Equal(t, username, payload.Username)
    require.WithinDuration(t, issuedAt, payload.IssuedAt, time.Second)
    require.WithinDuration(t, expiredAt, payload.ExpiredAt, time.Second)
}
```

OK, now we generate the token by calling `maker.CreatToken` function, and pass in the `username` and `duration`. Require no errors, and require the output token to not be empty.

Next, we call `maker.VerifyToken` to make sure that the token is valid and also get back its payload data. We require no errors, and require the payload object to be not empty.

Then we need to check all fields of the payload object.

- First the `payload.ID` should be not zero.
- Then the `payload.Username` should equal to the input `username`.
- We use `require.WithinDuration` to compare the `payload.IssuedAt` field with the expected `issuedAt` time we saved above. They should not be different by more than 1 second.
- Likewise, we compare the `payload.ExpiredAt` field with the expected `expiredAt` time in the same manner.

And we’re done! Let’s run this unit test!

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zcfcjgfjezdeb3cwhj5p.png)

It passed. Cool! So that’s how we test the happy case.

Now let’s add another test to check the expired JWT token case.

Similar as before, we first have to create a new `JWTMaker`. Then we will create an expired token by calling `maker.CreateToken()`, pass in a random `username` and a `negative duration`.

```go
func TestExpiredJWTToken(t *testing.T) {
    maker, err := NewJWTMaker(util.RandomString(32))
    require.NoError(t, err)

    token, err := maker.CreateToken(util.RandomOwner(), -time.Minute)
    require.NoError(t, err)
    require.NotEmpty(t, token)

    payload, err := maker.VerifyToken(token)
    require.Error(t, err)
    require.EqualError(t, err, ErrExpiredToken.Error())
    require.Nil(t, payload)
}
```

We require no errors to be returned, and the token should not be empty. Now we will verify this output token.

This time, we expect an error to be returned. And more specifically, it should be `ErrExpiredToken`. Finally, the output payload should be `nil`.

OK, let’s run the test!

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xco8j6bxspaxzxesar6k.png)

It passed. Excellent!

The last test we’re gonna write is to check the invalid token case, where a `None` algorithm header is used. This is a well-known attack technique that I have told you in the previous lecture.

First I’m gonna create a new `payload` with a random `username` and a `duration` of 1 minute. Require no errors. Then let’s make a new token by calling `jwt.NewWithClaims()` with the `jwt.SigningMethodNone` and the created `payload`.

Now we have to sign this token using the `SignedString()` method. But we cannot just use any random secret key here, because the jwt-go library has completely forbidden from using the `None` algorithm to sign the token.

We can only use it for testing when we pass in this special constant: `jwt.UnsafeAllowNoneSignatureType` as the secret key.

If you follow the implementation of this value, you can see that normally the None sign method is disallowed, unless the input key is this special constant. It basically means that you’re aware of what you’re doing. Make sure you only use it for testing, and not for production.

```go
func TestInvalidJWTTokenAlgNone(t *testing.T) {
    payload, err := NewPayload(util.RandomOwner(), time.Minute)
    require.NoError(t, err)

    jwtToken := jwt.NewWithClaims(jwt.SigningMethodNone, payload)
    token, err := jwtToken.SignedString(jwt.UnsafeAllowNoneSignatureType)
    require.NoError(t, err)

    maker, err := NewJWTMaker(util.RandomString(32))
    require.NoError(t, err)

    payload, err = maker.VerifyToken(token)
    require.Error(t, err)
    require.EqualError(t, err, ErrInvalidToken.Error())
    require.Nil(t, payload)
}
```

OK let’s get back to our code. We have to create a new `JWTMaker` as in the other tests. And now we call `maker.VerifyToken()` to verify the token we’ve signed above.

This time, the function should also return an error, and the error should be equal to `ErrInvalidToken`. The output payload should also be `nil`.

Alright, now let’s run the test!

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7vn2368lzjailcfnlg0c.png)

It passed! Awesome!

So now you know how to implement and test JWT in go.

Although I think the jwt-go package was quite well implemented in terms of preventing security mistakes, it’s still a bit complicated and difficult to use than necessary, especially for the token verification part.

## Implement PASETO Maker

Now I’m gonna show you how to implement the same token maker interface but using PASETO instead. It would be much easier and cleaner than JWT.

OK, let’s open the browser and search for `paseto golang`. Open its Github page and copy the URL: <https://github.com/o1egl/paseto>. Then run `go get` with this URL to download the package:

```bash
go get github.com/o1egl/paseto
```

Now get back to our project, I’m gonna create a new file: `paseto_maker.go` inside the `token` folder.

Similar to what we’ve done with JWT, Let’s declare a type `PasetoMaker` struct, which will implement the same `token.Maker` interface, but use PASETO instead of JWT.

We’re gonna use the latest version of PASETO at the moment, which is version 2. So the `PasetoMaker` struct will have a `paseto` field of type `paseto.V2`.

```go
type PasetoMaker struct {
    paseto       *paseto.V2
    symmetricKey []byte
}
```

And as I just want to use the token locally for our banking API, we will use symmetric encryption to encrypt the token payload. Therefore, we need a field to store the `symmetricKey` here.

OK now let’s add a function `NewPasetoMaker()`, which  takes a `symmetricKey` string as input, and returns a `token.Maker` interface or an `error`. This function will create a new `PasetoMaker` instance.

Paseto version 2 uses [Chacha20 Poly1305](https://tools.ietf.org/html/rfc7539) algorithm to encrypt the payload. So here we have to check the length of the symmetric key to make sure that it has the correct size that’s required by the algorithm.

```go
import (
    "github.com/aead/chacha20poly1305"
    "github.com/o1egl/paseto"
)

func NewPasetoMaker(symmetricKey string) (Maker, error) {
    if len(symmetricKey) != chacha20poly1305.KeySize {
        return nil, fmt.Errorf("invalid key size: must be exactly %d characters", chacha20poly1305.KeySize)
    }

    maker := &PasetoMaker{
        paseto:       paseto.NewV2(),
        symmetricKey: []byte(symmetricKey),
    }

    return maker, nil
}
```

If the key length is not correct then we just return a nil object and an error saying invalid key size. It must have exactly this number of characters.

Else, we just create a new PasetoMaker object that contains `paseto.NewV2()` and the input `symmetricKey` converted to `[]byte` slice.

Then we return this `maker` object and a `nil` error.

Again, here we see a red line under maker object because it’s not implementing the `token.Maker` interface yet. So let’s do the same as what we’ve done for `JWTMaker`.

I’m gonna copy these 2 required methods of the token maker interface, and add the `PasetoMaker` receiver in front of them.

```go
func (maker *PasetoMaker) CreateToken(username string, duration time.Duration) (string, error) {}

func (maker *PasetoMaker) VerifyToken(token string) (*Payload, error) {}
```

OK, now the red line is gone. Let’s implement the `CreateToken()` method.

### Implement PASETO CreateToken method

Similar as before, we first have to create a new `payload`  with the input `username` and `duration`. If error is not `nil`, we return an empty string and the error to the caller.

Otherwise, we return `maker.paseto.Encrypt()`, and pass in the `maker.symmetricKey`, and the `payload` object. The last argument is an optional footer, which we don’t need, so I put `nil` here.

```go
func (maker *PasetoMaker) CreateToken(username string, duration time.Duration) (string, error) {
    payload, err := NewPayload(username, duration)
    if err != nil {
        return "", err
    }

    return maker.paseto.Encrypt(maker.symmetricKey, payload, nil)
}

```

And that’s it! Pretty short and simple, right?

If we follow the implementation of this `Encrypt()` function, we can see that, it is using `Chacha Poly` cipher algorithm.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/g6513zdr7jbpywiw3t37.png)

And inside the `newCipher()` function, it also checks the input `key size` to make sure that it equals to `32 bytes`.

### Implement PASETO VerifyToken method

Alright, now let’s go back to our code and implement the `VerifyToken()` method. It’s very simple!

We just need to declare an empty `payload` object to store the decrypted data. Then call `maker.paseto.Decrypt()` with the input `token`, the `symmetricKey`, the `payload` and a `nil` footer.

```go
func (maker *PasetoMaker) VerifyToken(token string) (*Payload, error) {
    payload := &Payload{}

    err := maker.paseto.Decrypt(token, maker.symmetricKey, payload, nil)
    if err != nil {
        return nil, ErrInvalidToken
    }

    err = payload.Valid()
    if err != nil {
        return nil, err
    }

    return payload, nil
}
```

If `error` is not `nil`, we return `nil` payload an `ErrInvalidToken`. Else, we will check if the token is valid or not by calling `payload.Valid()`.

If there’s an error, we just return `nil` payload and the `error` itself. Otherwise, we return the `payload` and a `nil` error.

And that’s it! Very concise and much simpler than JWT, right?

### Test PASETO Maker

OK, now let’s write some unit tests!

I’m gonna create a new file: `paseto_maker_test.go` inside the `token` package. Actually the test would be almost identical to the one we wrote for JWT, so I’m just gonna copy it here.

Change its name to `TestPasetoMaker`. Then here, instead of `NewJWTMaker()`, we call `NewPasetoMaker()`.

```go
func TestPasetoMaker(t *testing.T) {
    maker, err := NewPasetoMaker(util.RandomString(32))
    require.NoError(t, err)

    username := util.RandomOwner()
    duration := time.Minute

    issuedAt := time.Now()
    expiredAt := issuedAt.Add(duration)

    token, err := maker.CreateToken(username, duration)
    require.NoError(t, err)
    require.NotEmpty(t, token)

    payload, err := maker.VerifyToken(token)
    require.NoError(t, err)
    require.NotEmpty(t, token)

    require.NotZero(t, payload.ID)
    require.Equal(t, username, payload.Username)
    require.WithinDuration(t, issuedAt, payload.IssuedAt, time.Second)
    require.WithinDuration(t, expiredAt, payload.ExpiredAt, time.Second)
}
```

We don’t have to change anything else because `PasetoMaker` implements the same `token.Maker` interface as `JWTMaker`.

Let’s run the test!

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/f2ac4porvj27fmpx13y6.png)

It passed!

Now let’s copy the test for the expired token case! Change its name to `TestExpiredPasetoToken`, and update this call to `NewPasetoMaker()`.

```go
func TestExpiredPasetoToken(t *testing.T) {
    maker, err := NewPasetoMaker(util.RandomString(32))
    require.NoError(t, err)

    token, err := maker.CreateToken(util.RandomOwner(), -time.Minute)
    require.NoError(t, err)
    require.NotEmpty(t, token)

    payload, err := maker.VerifyToken(token)
    require.Error(t, err)
    require.EqualError(t, err, ErrExpiredToken.Error())
    require.Nil(t, payload)
}
```

Then run the test!

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nvmkbh05oyj1dwr47wit.png)

It also passed. Excellent!

We don’t need the last test because the `None` algorithm just doesn’t exist in PASETO. You can write another test to check the invalid token case if you want. I leave it as an exercise for you to practice.

And that brings us to the end of this lecture. We have learned how to implement both JWT and PASETO using Go to create and verify access tokens.

In the next article, I will show you how to use them in the login API, where users provide their username & password, and the server will return an access token if the provided credentials are correct.

Thanks a lot for reading, and see you soon in the next lecture!

---

If you like the article, please subscribe to our [Youtube channel](http://bit.ly/techschoolguru) and follow us on [Twitter](https://twitter.com/techschoolguru) or [Facebook](https://www.facebook.com/techschool.guru) for more tutorials in the future.

---
If you want to join me on my current amazing team at Voodoo, check out [our job openings here](https://bit.ly/voodoojobs). Remote or onsite in Paris/Amsterdam/London/Berlin/Barcelona with visa sponsorship.