Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions .drone.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
---
type: docker
kind: pipeline
name: "Main"

steps:
- name: Docker build Git SHA
image: plugins/docker:20
pull: if-not-exists
environment:
DOCKER_BUILDKIT: 1
settings:
username:
from_secret: quay_username
password:
from_secret: quay_password
repo: quay.io/openware/gotrue
registry: quay.io
tag: ${DRONE_COMMIT:0:7}
purge: false
when:
event:
- push
branch:
- stable/ow
- feature/asymmetric-auth
7 changes: 6 additions & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ ENV GO111MODULE=on
ENV CGO_ENABLED=0
ENV GOOS=linux

RUN apk add --no-cache make git
RUN apk add --no-cache make git curl

WORKDIR /go/src/github.com/netlify/gotrue

Expand All @@ -15,11 +15,16 @@ RUN make deps
COPY . /go/src/github.com/netlify/gotrue
RUN make build

ARG KAIGARA_VERSION=v1.0.10
RUN curl -Lo ./kaigara https://github.com/openware/kaigara/releases/download/${KAIGARA_VERSION}/kaigara \
&& chmod +x ./kaigara

FROM alpine:3.17
RUN adduser -D -u 1000 netlify

RUN apk add --no-cache ca-certificates
COPY --from=build /go/src/github.com/netlify/gotrue/gotrue /usr/local/bin/gotrue
COPY --from=build /go/src/github.com/netlify/gotrue/kaigara /usr/local/bin/kaigara
COPY --from=build /go/src/github.com/netlify/gotrue/migrations /usr/local/etc/gotrue/migrations/

ENV GOTRUE_DB_MIGRATIONS_PATH /usr/local/etc/gotrue/migrations
Expand Down
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -395,13 +395,17 @@ by default.

```properties
GOTRUE_JWT_SECRET=supersecretvalue
GOTRUE_JWT_ALGORITHM=RS256
GOTRUE_JWT_EXP=3600
GOTRUE_JWT_AUD=netlify
```
`JWT_ALGORITHM` - `string`

The signing algorithm for the JWT. Defaults to HS256.

`JWT_SECRET` - `string` **required**

The secret used to sign JWT tokens with.
The secret used to sign JWT tokens with. If signing alogrithm is RS256, secret has to be Base64 encoded RSA private key.

`JWT_EXP` - `number`

Expand Down
5 changes: 3 additions & 2 deletions api/admin_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,12 @@ import (
"time"

jwt "github.com/golang-jwt/jwt"
"github.com/netlify/gotrue/conf"
"github.com/netlify/gotrue/models"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/stretchr/testify/suite"

"github.com/netlify/gotrue/conf"
"github.com/netlify/gotrue/models"
)

type AdminTestSuite struct {
Expand Down
9 changes: 6 additions & 3 deletions api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,16 @@ import (
"github.com/didip/tollbooth/v5"
"github.com/didip/tollbooth/v5/limiter"
"github.com/go-chi/chi"
"github.com/sirupsen/logrus"

"github.com/netlify/gotrue/conf"
"github.com/netlify/gotrue/mailer"
"github.com/netlify/gotrue/observability"
"github.com/netlify/gotrue/storage"

"github.com/rs/cors"
"github.com/sebest/xff"
"github.com/sirupsen/logrus"

"github.com/netlify/gotrue/mailer"
"github.com/netlify/gotrue/observability"
)

const (
Expand Down
9 changes: 5 additions & 4 deletions api/audit_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,12 @@ import (
"time"

jwt "github.com/golang-jwt/jwt"
"github.com/netlify/gotrue/conf"
"github.com/netlify/gotrue/models"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/stretchr/testify/suite"

"github.com/netlify/gotrue/conf"
"github.com/netlify/gotrue/models"
)

type AuditTestSuite struct {
Expand Down Expand Up @@ -49,12 +50,12 @@ func (ts *AuditTestSuite) makeSuperAdmin(email string) string {
u.Role = "supabase_admin"

var token string
token, err = generateAccessToken(ts.API.db, u, nil, time.Second*time.Duration(ts.Config.JWT.Exp), ts.Config.JWT.Secret)
token, err = generateAccessToken(ts.API.db, u, nil, time.Second*time.Duration(ts.Config.JWT.Exp), ts.Config.JWT.GetSigningMethod(), ts.Config.JWT.GetSigningKey())
require.NoError(ts.T(), err, "Error generating access token")

p := jwt.Parser{ValidMethods: []string{jwt.SigningMethodHS256.Name}}
_, err = p.Parse(token, func(token *jwt.Token) (interface{}, error) {
return []byte(ts.Config.JWT.Secret), nil
return ts.Config.JWT.GetVerificationKey(), nil
})
require.NoError(ts.T(), err, "Error parsing token")

Expand Down
5 changes: 3 additions & 2 deletions api/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (

"github.com/gofrs/uuid"
jwt "github.com/golang-jwt/jwt"

"github.com/netlify/gotrue/models"
"github.com/netlify/gotrue/storage"
)
Expand Down Expand Up @@ -68,9 +69,9 @@ func (a *API) parseJWTClaims(bearer string, r *http.Request) (context.Context, e
ctx := r.Context()
config := a.config

p := jwt.Parser{ValidMethods: []string{jwt.SigningMethodHS256.Name}}
p := jwt.Parser{ValidMethods: []string{config.JWT.Algorithm}}
token, err := p.ParseWithClaims(bearer, &GoTrueClaims{}, func(token *jwt.Token) (interface{}, error) {
return []byte(config.JWT.Secret), nil
return config.JWT.GetVerificationKey(), nil
})
if err != nil {
return nil, unauthorizedError("invalid JWT: unable to parse or verify signature, %v", err)
Expand Down
8 changes: 4 additions & 4 deletions api/external.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ func (a *API) ExternalProviderRedirect(w http.ResponseWriter, r *http.Request) e
log := observability.GetLogEntry(r)
log.WithField("provider", providerType).Info("Redirecting to external provider")

token := jwt.NewWithClaims(jwt.SigningMethodHS256, ExternalProviderClaims{
token := jwt.NewWithClaims(config.JWT.GetSigningMethod(), ExternalProviderClaims{
NetlifyMicroserviceClaims: NetlifyMicroserviceClaims{
StandardClaims: jwt.StandardClaims{
ExpiresAt: time.Now().Add(5 * time.Minute).Unix(),
Expand All @@ -77,7 +77,7 @@ func (a *API) ExternalProviderRedirect(w http.ResponseWriter, r *http.Request) e
InviteToken: inviteToken,
Referrer: redirectURL,
})
tokenString, err := token.SignedString([]byte(config.JWT.Secret))
tokenString, err := token.SignedString(config.JWT.GetSigningKey())
if err != nil {
return internalServerError("Error creating state").WithInternalError(err)
}
Expand Down Expand Up @@ -424,9 +424,9 @@ func (a *API) processInvite(r *http.Request, ctx context.Context, tx *storage.Co
func (a *API) loadExternalState(ctx context.Context, state string) (context.Context, error) {
config := a.config
claims := ExternalProviderClaims{}
p := jwt.Parser{ValidMethods: []string{jwt.SigningMethodHS256.Name}}
p := jwt.Parser{ValidMethods: []string{config.JWT.Algorithm}}
_, err := p.ParseWithClaims(state, &claims, func(token *jwt.Token) (interface{}, error) {
return []byte(config.JWT.Secret), nil
return config.JWT.GetVerificationKey(), nil
})
if err != nil || claims.Provider == "" {
return nil, badRequestError("OAuth state is invalid: %v", err)
Expand Down
2 changes: 1 addition & 1 deletion api/external_apple_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ func (ts *ExternalTestSuite) TestSignupExternalApple() {
claims := ExternalProviderClaims{}
p := jwt.Parser{ValidMethods: []string{jwt.SigningMethodHS256.Name}}
_, err = p.ParseWithClaims(q.Get("state"), &claims, func(token *jwt.Token) (interface{}, error) {
return []byte(ts.Config.JWT.Secret), nil
return ts.Config.JWT.GetVerificationKey(), nil
})
ts.Require().NoError(err)

Expand Down
2 changes: 1 addition & 1 deletion api/external_azure_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ func (ts *ExternalTestSuite) TestSignupExternalAzure() {
claims := ExternalProviderClaims{}
p := jwt.Parser{ValidMethods: []string{jwt.SigningMethodHS256.Name}}
_, err = p.ParseWithClaims(q.Get("state"), &claims, func(token *jwt.Token) (interface{}, error) {
return []byte(ts.Config.JWT.Secret), nil
return ts.Config.JWT.GetVerificationKey(), nil
})
ts.Require().NoError(err)

Expand Down
2 changes: 1 addition & 1 deletion api/external_bitbucket_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ func (ts *ExternalTestSuite) TestSignupExternalBitbucket() {
claims := ExternalProviderClaims{}
p := jwt.Parser{ValidMethods: []string{jwt.SigningMethodHS256.Name}}
_, err = p.ParseWithClaims(q.Get("state"), &claims, func(token *jwt.Token) (interface{}, error) {
return []byte(ts.Config.JWT.Secret), nil
return ts.Config.JWT.GetVerificationKey(), nil
})
ts.Require().NoError(err)

Expand Down
2 changes: 1 addition & 1 deletion api/external_discord_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ func (ts *ExternalTestSuite) TestSignupExternalDiscord() {
claims := ExternalProviderClaims{}
p := jwt.Parser{ValidMethods: []string{jwt.SigningMethodHS256.Name}}
_, err = p.ParseWithClaims(q.Get("state"), &claims, func(token *jwt.Token) (interface{}, error) {
return []byte(ts.Config.JWT.Secret), nil
return ts.Config.JWT.GetVerificationKey(), nil
})
ts.Require().NoError(err)

Expand Down
2 changes: 1 addition & 1 deletion api/external_facebook_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ func (ts *ExternalTestSuite) TestSignupExternalFacebook() {
claims := ExternalProviderClaims{}
p := jwt.Parser{ValidMethods: []string{jwt.SigningMethodHS256.Name}}
_, err = p.ParseWithClaims(q.Get("state"), &claims, func(token *jwt.Token) (interface{}, error) {
return []byte(ts.Config.JWT.Secret), nil
return ts.Config.JWT.GetVerificationKey(), nil
})
ts.Require().NoError(err)

Expand Down
2 changes: 1 addition & 1 deletion api/external_github_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ func (ts *ExternalTestSuite) TestSignupExternalGithub() {
claims := ExternalProviderClaims{}
p := jwt.Parser{ValidMethods: []string{jwt.SigningMethodHS256.Name}}
_, err = p.ParseWithClaims(q.Get("state"), &claims, func(token *jwt.Token) (interface{}, error) {
return []byte(ts.Config.JWT.Secret), nil
return ts.Config.JWT.GetVerificationKey(), nil
})
ts.Require().NoError(err)

Expand Down
2 changes: 1 addition & 1 deletion api/external_gitlab_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ func (ts *ExternalTestSuite) TestSignupExternalGitlab() {
claims := ExternalProviderClaims{}
p := jwt.Parser{ValidMethods: []string{jwt.SigningMethodHS256.Name}}
_, err = p.ParseWithClaims(q.Get("state"), &claims, func(token *jwt.Token) (interface{}, error) {
return []byte(ts.Config.JWT.Secret), nil
return ts.Config.JWT.GetVerificationKey(), nil
})
ts.Require().NoError(err)

Expand Down
2 changes: 1 addition & 1 deletion api/external_google_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ func (ts *ExternalTestSuite) TestSignupExternalGoogle() {
claims := ExternalProviderClaims{}
p := jwt.Parser{ValidMethods: []string{jwt.SigningMethodHS256.Name}}
_, err = p.ParseWithClaims(q.Get("state"), &claims, func(token *jwt.Token) (interface{}, error) {
return []byte(ts.Config.JWT.Secret), nil
return ts.Config.JWT.GetVerificationKey(), nil
})
ts.Require().NoError(err)

Expand Down
2 changes: 1 addition & 1 deletion api/external_twitch_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ func (ts *ExternalTestSuite) TestSignupExternalTwitch() {
claims := ExternalProviderClaims{}
p := jwt.Parser{ValidMethods: []string{jwt.SigningMethodHS256.Name}}
_, err = p.ParseWithClaims(q.Get("state"), &claims, func(token *jwt.Token) (interface{}, error) {
return []byte(ts.Config.JWT.Secret), nil
return ts.Config.JWT.GetVerificationKey(), nil
})
ts.Require().NoError(err)

Expand Down
10 changes: 5 additions & 5 deletions api/invite_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,12 @@ import (
"time"

jwt "github.com/golang-jwt/jwt"
"github.com/netlify/gotrue/conf"
"github.com/netlify/gotrue/models"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/stretchr/testify/suite"

"github.com/netlify/gotrue/conf"
"github.com/netlify/gotrue/models"
)

type InviteTestSuite struct {
Expand Down Expand Up @@ -59,13 +60,12 @@ func (ts *InviteTestSuite) makeSuperAdmin(email string) string {
u.Role = "supabase_admin"

var token string
token, err = generateAccessToken(ts.API.db, u, nil, time.Second*time.Duration(ts.Config.JWT.Exp), ts.Config.JWT.Secret)

token, err = generateAccessToken(ts.API.db, u, nil, time.Second*time.Duration(ts.Config.JWT.Exp), ts.Config.JWT.GetSigningMethod(), ts.Config.JWT.GetSigningKey())
require.NoError(ts.T(), err, "Error generating access token")

p := jwt.Parser{ValidMethods: []string{jwt.SigningMethodHS256.Name}}
_, err = p.Parse(token, func(token *jwt.Token) (interface{}, error) {
return []byte(ts.Config.JWT.Secret), nil
return ts.Config.JWT.GetVerificationKey(), nil
})
require.NoError(ts.T(), err, "Error parsing token")

Expand Down
7 changes: 4 additions & 3 deletions api/logout_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,11 @@ import (
"testing"
"time"

"github.com/netlify/gotrue/conf"
"github.com/netlify/gotrue/models"
"github.com/stretchr/testify/require"
"github.com/stretchr/testify/suite"

"github.com/netlify/gotrue/conf"
"github.com/netlify/gotrue/models"
)

type LogoutTestSuite struct {
Expand Down Expand Up @@ -42,7 +43,7 @@ func (ts *LogoutTestSuite) SetupTest() {

// generate access token to use for logout
var t string
t, err = generateAccessToken(ts.API.db, u, nil, time.Second*time.Duration(ts.Config.JWT.Exp), ts.Config.JWT.Secret)
t, err = generateAccessToken(ts.API.db, u, nil, time.Second*time.Duration(ts.Config.JWT.Exp), ts.Config.JWT.GetSigningMethod(), ts.Config.JWT.GetSigningKey())
require.NoError(ts.T(), err)
ts.token = t
}
Expand Down
13 changes: 7 additions & 6 deletions api/mfa_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,11 @@ import (
"testing"
"time"

"github.com/pquerna/otp"

"github.com/netlify/gotrue/conf"
"github.com/netlify/gotrue/models"
"github.com/netlify/gotrue/utilities"
"github.com/pquerna/otp"

"github.com/jackc/pgx/v4"

Expand Down Expand Up @@ -124,7 +125,7 @@ func (ts *MFATestSuite) TestEnrollFactor() {
user, err := models.FindUserByEmailAndAudience(ts.API.db, "[email protected]", ts.Config.JWT.Aud)
ts.Require().NoError(err)

token, err := generateAccessToken(ts.API.db, user, nil, time.Second*time.Duration(ts.Config.JWT.Exp), ts.Config.JWT.Secret)
token, err := generateAccessToken(ts.API.db, user, nil, time.Second*time.Duration(ts.Config.JWT.Exp), ts.Config.JWT.GetSigningMethod(), ts.Config.JWT.GetSigningKey())
require.NoError(ts.T(), err)

w := httptest.NewRecorder()
Expand Down Expand Up @@ -161,7 +162,7 @@ func (ts *MFATestSuite) TestChallengeFactor() {
require.NoError(ts.T(), err)
f := factors[0]

token, err := generateAccessToken(ts.API.db, u, nil, time.Second*time.Duration(ts.Config.JWT.Exp), ts.Config.JWT.Secret)
token, err := generateAccessToken(ts.API.db, u, nil, time.Second*time.Duration(ts.Config.JWT.Exp), ts.Config.JWT.GetSigningMethod(), ts.Config.JWT.GetSigningKey())
require.NoError(ts.T(), err, "Error generating access token")

var buffer bytes.Buffer
Expand Down Expand Up @@ -222,7 +223,7 @@ func (ts *MFATestSuite) TestMFAVerifyFactor() {
secondarySession.FactorID = &f.ID
require.NoError(ts.T(), ts.API.db.Create(secondarySession), "Error saving test session")

token, err := generateAccessToken(ts.API.db, user, r.SessionId, time.Second*time.Duration(ts.Config.JWT.Exp), ts.Config.JWT.Secret)
token, err := generateAccessToken(ts.API.db, user, r.SessionId, time.Second*time.Duration(ts.Config.JWT.Exp), ts.Config.JWT.GetSigningMethod(), ts.Config.JWT.GetSigningKey())

require.NoError(ts.T(), err)

Expand Down Expand Up @@ -318,7 +319,7 @@ func (ts *MFATestSuite) TestUnenrollVerifiedFactor() {

var buffer bytes.Buffer

token, err := generateAccessToken(ts.API.db, u, &s.ID, time.Second*time.Duration(ts.Config.JWT.Exp), ts.Config.JWT.Secret)
token, err := generateAccessToken(ts.API.db, u, &s.ID, time.Second*time.Duration(ts.Config.JWT.Exp), ts.Config.JWT.GetSigningMethod(), ts.Config.JWT.GetSigningKey())
require.NoError(ts.T(), err)

w := httptest.NewRecorder()
Expand Down Expand Up @@ -360,7 +361,7 @@ func (ts *MFATestSuite) TestUnenrollUnverifiedFactor() {

var buffer bytes.Buffer

token, err := generateAccessToken(ts.API.db, u, &s.ID, time.Second*time.Duration(ts.Config.JWT.Exp), ts.Config.JWT.Secret)
token, err := generateAccessToken(ts.API.db, u, &s.ID, time.Second*time.Duration(ts.Config.JWT.Exp), ts.Config.JWT.GetSigningMethod(), ts.Config.JWT.GetSigningKey())
require.NoError(ts.T(), err)
require.NoError(ts.T(), json.NewEncoder(&buffer).Encode(map[string]interface{}{
"factor_id": f.ID,
Expand Down
Loading