Skip to content

Commit

Permalink
Merge pull request #82 from okta/pkce_utility
Browse files Browse the repository at this point in the history
PKCE utility
  • Loading branch information
monde authored Mar 17, 2022
2 parents 0dd48df + 03b8e7a commit 3d7d160
Show file tree
Hide file tree
Showing 15 changed files with 313 additions and 18 deletions.
43 changes: 43 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# This GitHub action can publish assets for release when a tag is created.
# Currently its setup to run on any tag that matches the pattern "v*" (ie. v0.1.0).
#
# This uses an action (hashicorp/ghaction-import-gpg) that assumes you set your
# private key in the `GPG_PRIVATE_KEY` secret and passphrase in the `PASSPHRASE`
# secret. If you would rather own your own GPG handling, please fork this action
# or use an alternative one for key handling.
#
# You will need to pass the `--batch` flag to `gpg` in your signing step
# in `goreleaser` to indicate this is being used in a non-interactive mode.
#
name: release
on:
push:
branches: [ master ]
tags:
- 'v*'
jobs:
goreleaser:
runs-on: ubuntu-latest
steps:
-
name: Checkout
uses: actions/[email protected]
-
name: Unshallow
run: git fetch --prune --unshallow
-
name: Set up Go
uses: actions/[email protected]
with:
go-version: 1.17
-
name: Run GoReleaser
uses: goreleaser/[email protected]
with:
version: latest
args: release --rm-dist
env:
GPG_FINGERPRINT: ${{ steps.import_gpg.outputs.fingerprint }}
# GitHub sets this automatically
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Changelog

## v1.3.0 (March 17th, 2022)

### Enhancements:

* New PCKE code verifier utility. [#81](https://github.com/okta/okta-jwt-verifier-golang/pull/81). Thanks, [@deepu105](https://github.com/deepu105)!

## v1.2.1 (February 16, 2022)

### Updates
Expand Down
2 changes: 1 addition & 1 deletion LICENSE.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
Copyright (c) 2015-2018 Okta Inc.
Copyright (c) 2015-Present Okta Inc.

Apache License
Version 2.0, January 2004
Expand Down
52 changes: 43 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@ This library helps you verify tokens that have been issued by Okta. To learn mor

This library uses semantic versioning and follows Okta's [library version policy](https://developer.okta.com/code/library-versions/).

| Version | Status |
| ------- | ---------------------------------- |
| 0.x | :warning: Beta Release (Retired) |
| 1.x | :heavy_check_mark: Release |

| Version | Status |
| ------- | -------------------------------- |
| 0.x | :warning: Beta Release (Retired) |
| 1.x | :heavy_check_mark: Release |

## Installation

```sh
go get -u github.com/okta/okta-jwt-verifier-golang
```
Expand All @@ -21,10 +21,11 @@ go get -u github.com/okta/okta-jwt-verifier-golang

This library was built to keep configuration to a minimum. To get it running at its most basic form, all you need to provide is the the following information:

- **Issuer** - This is the URL of the authorization server that will perform authentication. All Developer Accounts have a "default" authorization server. The issuer is a combination of your Org URL (found in the upper right of the console home page) and `/oauth2/default`. For example, `https://dev-1234.oktapreview.com/oauth2/default`.
- **Issuer** - This is the URL of the authorization server that will perform authentication. All Developer Accounts have a "default" authorization server. The issuer is a combination of your Org URL (found in the upper right of the console home page) and `/oauth2/default`. For example, `https://dev-1234.oktapreview.com/oauth2/default`.
- **Client ID**- These can be found on the "General" tab of the Web application that you created earlier in the Okta Developer Console.

#### Access Token Validation

```go
import "github.com/okta/okta-jwt-verifier-golang"

Expand All @@ -43,6 +44,7 @@ token, err := verifier.VerifyAccessToken("{JWT}")
```

#### Id Token Validation

```go
import "github.com/okta/okta-jwt-verifier-golang"

Expand All @@ -69,7 +71,8 @@ sub := token.Claims["sub"]
```

#### Dealing with clock skew
We default to a two minute clock skew adjustment in our validation. If you need to change this, you can use the `SetLeeway` method:

We default to a two minute clock skew adjustment in our validation. If you need to change this, you can use the `SetLeeway` method:

```go
jwtVerifierSetup := JwtVerifier{
Expand All @@ -88,7 +91,7 @@ expiry and 10 minute purge setting that is used to store resources fetched over
HTTP. It also defines a `Cacher` interface with a `Get` method allowing
customization of that caching. If you want to establish your own caching
strategy then provide your own `Cacher` object that implements that interface.
Your custom cache is set in the verifier via the `Cache` attribute. See the
Your custom cache is set in the verifier via the `Cache` attribute. See the
example in the [cache example test](utils/cache_example_test.go) that shows a
"forever" cache (that one would never use in production ...)

Expand All @@ -101,6 +104,38 @@ jwtVerifierSetup := jwtverifier.JwtVerifier{
verifier := jwtVerifierSetup.New()
```

#### Utilities

The below utilities are available in this package that can be used for Authentication flows

**Nonce Generator**

```go
import jwtUtils "github.com/okta/okta-jwt-verifier-golang/utils"

nonce, err := jwtUtils.GenerateNonce()
```

**PKCE Code Verifier and Challenge Generator**

```go
import jwtUtils "github.com/okta/okta-jwt-verifier-golang/utils"

codeVerifier, err := jwtUtils.GenerateCodeVerifier()
// or
codeVerifier, err := jwtUtils.GenerateCodeVerifierWithLength(50)

// get string value for oauth2 code verifier
codeVerifierValue := codeVerifier.String()

// get plain text code challenge from verifier
codeChallengePlain := codeVerifier.CodeChallengePlain()
codeChallengeMethod := "plain"
// get sha256 code challenge from verifier
codeChallengeS256 := codeVerifier.CodeChallengeS256()
codeChallengeMethod := "S256"
```

## Testing

If you create a PR from a fork of okta/okta-jwt-verifier-golang the build for
Expand All @@ -120,4 +155,3 @@ with Implicit (hybrid) enabled.
```
go test -test.v
```

2 changes: 1 addition & 1 deletion adaptors/adaptor.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright 2018 Okta, Inc.
* Copyright 2018 - Present Okta, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down
2 changes: 1 addition & 1 deletion adaptors/lestrratGoJwx/lestrratGoJwx.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright 2018 Okta, Inc.
* Copyright 2018 - Present Okta, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down
2 changes: 1 addition & 1 deletion discovery/discovery.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright 2018 Okta, Inc.
* Copyright 2018 - Present Okta, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down
2 changes: 1 addition & 1 deletion discovery/oidc/oidc.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright 2018 Okta, Inc.
* Copyright 2018 - Present Okta, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down
2 changes: 1 addition & 1 deletion errors/JwtEmptyString.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright 2018 Okta, Inc.
* Copyright 2018 - Present Okta, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down
2 changes: 1 addition & 1 deletion jwtverifier.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright 2018 Okta, Inc.
* Copyright 2018 - Present Okta, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down
2 changes: 1 addition & 1 deletion jwtverifier_test.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright 2018 Okta, Inc.
* Copyright 2018 - Present Okta, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down
1 change: 1 addition & 0 deletions utils/nonce.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"fmt"
)

// GenerateNonce generates a random base64 encoded string suitable for OpenID nonce
func GenerateNonce() (string, error) {
nonceBytes := make([]byte, 32)
_, err := rand.Read(nonceBytes)
Expand Down
2 changes: 1 addition & 1 deletion utils/parseEnv.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright 2018 Okta, Inc.
* Copyright 2018 - Present Okta, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down
87 changes: 87 additions & 0 deletions utils/pkce_code_verifier.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
/*******************************************************************************
* Copyright 2022 - Present Okta, Inc.
*
* 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
*
* http://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.
******************************************************************************/

// based on https://datatracker.ietf.org/doc/html/rfc7636
package utils

import (
"crypto/sha256"
"encoding/base64"
"fmt"
"math/rand"
"strings"
)

const (
MinLength = 32
MaxLength = 96
)

type PKCECodeVerifier struct {
CodeVerifier string
}

func (v *PKCECodeVerifier) String() string {
return v.CodeVerifier
}

// CodeChallengePlain generates a plain code challenge from a code verifier
func (v *PKCECodeVerifier) CodeChallengePlain() string {
return v.CodeVerifier
}

// CodeChallengeS256 generates a Sha256 code challenge from a code verifier
func (v *PKCECodeVerifier) CodeChallengeS256() string {
h := sha256.New()
h.Write([]byte(v.CodeVerifier))
return encode(h.Sum(nil))
}

// GenerateCodeVerifier generates a code verifier with the minimum length
func GenerateCodeVerifier() (*PKCECodeVerifier, error) {
return GenerateCodeVerifierWithLength(MinLength)
}

// GenerateCodeVerifierWithLength generates a code verifier with the specified length
func GenerateCodeVerifierWithLength(length int) (*PKCECodeVerifier, error) {
if length < MinLength || length > MaxLength {
return nil, fmt.Errorf("invalid length: %v", length)
}
// create random bytes
b, err := bytes(length)
if err != nil {
return nil, err
}
return &PKCECodeVerifier{
CodeVerifier: encode(b),
}, nil
}

// bytes generates n random bytes
func bytes(n int) ([]byte, error) {
b := make([]byte, n)
_, err := rand.Read(b)
return b, err
}

// encode encodes a byte array to a base64 string with no padding
func encode(b []byte) string {
encoded := base64.StdEncoding.EncodeToString(b)
encoded = strings.Replace(encoded, "+", "-", -1)
encoded = strings.Replace(encoded, "/", "_", -1)
encoded = strings.Replace(encoded, "=", "", -1)
return encoded
}
Loading

0 comments on commit 3d7d160

Please sign in to comment.