Skip to content

Commit

Permalink
Merge pull request #72 from plivo/jwt
Browse files Browse the repository at this point in the history
add jwt helpers
  • Loading branch information
nixonsam authored May 28, 2020
2 parents fcd2612 + dd4f386 commit f0bb7a2
Show file tree
Hide file tree
Showing 5 changed files with 163 additions and 1 deletion.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# Change Log

## [4.7.0](https://github.com/plivo/plivo-go/tree/v4.7.0) (2020-05-28)
- Add JWT helper functions.

## [4.6.0](https://github.com/plivo/plivo-go/tree/v4.6.0) (2020-04-29)
- Add V3 signature helper functions.
Expand Down
2 changes: 1 addition & 1 deletion baseclient.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import (
"github.com/google/go-querystring/query"
)

const sdkVersion = "4.6.0"
const sdkVersion = "4.7.0"

type ClientOptions struct {
HttpClient *http.Client
Expand Down
26 changes: 26 additions & 0 deletions examples/jwt.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package main

import (
"log"
"time"

"github.com/plivo/plivo-go/plivo/jwt"
)

func main() {
token1 := jwt.AccessToken{}
err := token1.New("{authId}", "{authToken}", "{endpointUsername}", time.Now(), time.Duration(300)*time.Second, time.Time{}, "{uid}")
if err != nil {
log.Fatalf("abort: %+v\n", err)
}
token1.AddVoiceGrants(jwt.VoiceGrants{false, true})
log.Println(token1.ToJwt())

token2 := jwt.AccessToken{}
err = token2.New("{authId}", "{authToken}", "{endpointUsername}", time.Now(), 0, time.Now().Add(300*time.Second), "{uid}")
if err != nil {
log.Fatalf("abort: %+v\n", err)
}
token2.AddVoiceGrants(jwt.VoiceGrants{false, true})
log.Println(token2.ToJwt())
}
114 changes: 114 additions & 0 deletions jwt/jwt.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
package jwt

import (
"errors"
"fmt"
"os"
"time"

"github.com/dgrijalva/jwt-go"
)

type AccessToken struct {
AuthId string
Key string
Username string
ValidFrom time.Time
Lifetime time.Duration
Uid string
Grants Grants `json:"grants"`
}

type Grants struct {
Voice VoiceGrants `json:"voice"`
}

type VoiceGrants struct {
IncomingAllow bool `json:"incoming_allow"`
OutgoingAllow bool `json:"outgoing_allow"`
}

type JwtClaims struct {
jwt.StandardClaims
Grants Grants `json:"grants"`
}

func (acctkn *AccessToken) New(authId string, authToken string, username string, validFrom time.Time, lifetime time.Duration, validTill time.Time, uid string) error {
if len(authId) == 0 {
authId = os.Getenv("PLIVO_AUTH_ID")
}
if len(authId) == 0 {
return errors.New("authId not found")
}
acctkn.AuthId = authId
if len(authToken) == 0 {
authToken = os.Getenv("PLIVO_AUTH_TOKEN")
}
if len(authToken) == 0 {
return errors.New("authToken not found")
}
acctkn.Key = authToken
if len(username) == 0 {
return errors.New("username not found")
}
acctkn.Username = username

if lifetime != 0 && (lifetime < 180*time.Second || lifetime > 86400*time.Second) {
return errors.New("lifetime out of [180, 86400]")
}

if validFrom.IsZero() {
acctkn.Lifetime = lifetime
if lifetime == 0 {
acctkn.Lifetime = 86400 * time.Second
}
if validTill.IsZero() {
acctkn.ValidFrom = time.Now()
} else {
acctkn.ValidFrom = validTill.Add(-acctkn.Lifetime)
}
} else if validTill.IsZero() {
acctkn.Lifetime = lifetime
if lifetime == 0 {
acctkn.Lifetime = 86400 * time.Second
}
acctkn.ValidFrom = validFrom

} else {
if lifetime != 0 {
return errors.New("use any 2 of validFrom, lifetime and validTill")
}
acctkn.ValidFrom = validFrom
acctkn.Lifetime = validTill.Sub(validFrom)
}

acctkn.Uid = uid
if len(uid) == 0 {
acctkn.Uid = fmt.Sprintf("%s-%d", acctkn.Username, time.Now().UnixNano())
}

return nil
}

func (acctkn *AccessToken) AddVoiceGrants(grants VoiceGrants) {
acctkn.Grants = Grants{grants}
}

func (acctkn *AccessToken) ToJwt() string {
// Create the Claims
claims := JwtClaims{
jwt.StandardClaims{
Id: acctkn.Uid,
Issuer: acctkn.AuthId,
Subject: acctkn.Username,
NotBefore: acctkn.ValidFrom.Unix(),
ExpiresAt: acctkn.ValidFrom.Add(acctkn.Lifetime).Unix(),
},
acctkn.Grants,
}

token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
token.Header["cty"] = "plivo;v=1"
ss, _ := token.SignedString([]byte(acctkn.Key))
return ss
}
20 changes: 20 additions & 0 deletions jwt/jwt_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package jwt

import (
"testing"
"time"

"github.com/stretchr/testify/assert"
)

func TestJwt(t *testing.T) {
token := AccessToken{}
err := token.New("MADADADADADADADADADA", "qwerty", "username", time.Unix(12121212, 0), time.Duration(30) * time.Second, time.Time{}, "username-12345")
assert.EqualError(t, err, "lifetime out of [180, 86400]")
_ = token.New("MADADADADADADADADADA", "qwerty", "username", time.Unix(12121212, 0), time.Duration(300) * time.Second, time.Time{}, "username-12345")
token.AddVoiceGrants(VoiceGrants{true, true})
assert.Equal(t,
"eyJhbGciOiJIUzI1NiIsImN0eSI6InBsaXZvO3Y9MSIsInR5cCI6IkpXVCJ9.eyJleHAiOjEyMTIxNTEyLCJqdGkiOiJ1c2VybmFtZS0xMjM0NSIsImlzcyI6Ik1BREFEQURBREFEQURBREFEQURBIiwibmJmIjoxMjEyMTIxMiwic3ViIjoidXNlcm5hbWUiLCJncmFudHMiOnsidm9pY2UiOnsiaW5jb21pbmdfYWxsb3ciOnRydWUsIm91dGdvaW5nX2FsbG93Ijp0cnVlfX19.51cD6eyvu_wvQ_3ag2i_8_T4cvbkU__rnkyH2MBA5Nk",
token.ToJwt(),
)
}

0 comments on commit f0bb7a2

Please sign in to comment.