~emersion/sinwon

d8d9387ed07e008b52c67955e0b92bfe80337605 — Simon Ser 7 months ago f87f116
Check redirect URI param in token endpoint
4 files changed, 38 insertions(+), 28 deletions(-)

M db.go
M entity.go
M oauth2.go
M schema.sql
M db.go => db.go +2 -2
@@ 237,8 237,8 @@ func (db *DB) RevokeAccessTokens(ctx context.Context, clientID ID[*Client], user

func (db *DB) CreateAuthCode(ctx context.Context, code *AuthCode) error {
	return db.db.QueryRowContext(ctx, `
		INSERT INTO AuthCode(hash, created_at, user, client, scope)
		VALUES (:hash, :created_at, :user, :client, :scope)
		INSERT INTO AuthCode(hash, created_at, user, client, scope, redirect_uri)
		VALUES (:hash, :created_at, :user, :client, :scope, :redirect_uri)
		RETURNING id
	`, entityArgs(code)...).Scan(&code.ID)
}

M entity.go => entity.go +19 -22
@@ 231,37 231,34 @@ type AuthorizedClient struct {
}

type AuthCode struct {
	ID        ID[*AuthCode]
	Hash      []byte
	CreatedAt time.Time
	User      ID[*User]
	Client    ID[*Client]
	Scope     string
	ID          ID[*AuthCode]
	Hash        []byte
	CreatedAt   time.Time
	User        ID[*User]
	Client      ID[*Client]
	Scope       string
	RedirectURI string
}

func NewAuthCode(user ID[*User], client ID[*Client], scope string) (code *AuthCode, secret string, err error) {
func (code *AuthCode) Generate() (secret string, err error) {
	secret, hash, err := generateSecret()
	if err != nil {
		return nil, "", fmt.Errorf("failed to generate authentication code secret: %v", err)
	}
	code = &AuthCode{
		Hash:      hash,
		CreatedAt: time.Now(),
		User:      user,
		Client:    client,
		Scope:     scope,
		return "", fmt.Errorf("failed to generate authentication code secret: %v", err)
	}
	return code, secret, nil
	code.Hash = hash
	code.CreatedAt = time.Now()
	return secret, nil
}

func (code *AuthCode) columns() map[string]interface{} {
	return map[string]interface{}{
		"id":         &code.ID,
		"hash":       &code.Hash,
		"created_at": &code.CreatedAt,
		"user":       &code.User,
		"client":     &code.Client,
		"scope":      (*nullString)(&code.Scope),
		"id":           &code.ID,
		"hash":         &code.Hash,
		"created_at":   &code.CreatedAt,
		"user":         &code.User,
		"client":       &code.Client,
		"scope":        (*nullString)(&code.Scope),
		"redirect_uri": (*nullString)(&code.RedirectURI),
	}
}


M oauth2.go => oauth2.go +16 -4
@@ 158,13 158,19 @@ func authorize(w http.ResponseWriter, req *http.Request) {
		return
	}

	authCode, secret, err := NewAuthCode(loginToken.User, client.ID, scope)
	authCode := AuthCode{
		User:        loginToken.User,
		Client:      client.ID,
		Scope:       scope,
		RedirectURI: rawRedirectURI,
	}
	secret, err := authCode.Generate()
	if err != nil {
		httpError(w, fmt.Errorf("failed to generate authentication code: %v", err))
		return
	}

	if err := db.CreateAuthCode(ctx, authCode); err != nil {
	if err := db.CreateAuthCode(ctx, &authCode); err != nil {
		httpError(w, fmt.Errorf("failed to create authentication code: %v", err))
		return
	}


@@ 195,6 201,7 @@ func exchangeToken(w http.ResponseWriter, req *http.Request) {
	clientID := values.Get("client_id")
	grantType := oauth2.GrantType(values.Get("grant_type"))
	scope := values.Get("scope")
	redirectURI := values.Get("redirect_uri")

	authClientID, clientSecret, _ := req.BasicAuth()
	if clientID == "" && authClientID == "" {


@@ 263,8 270,13 @@ func exchangeToken(w http.ResponseWriter, req *http.Request) {
		})
		return
	}

	// TODO: check redirect_uri
	if redirectURI != authCode.RedirectURI {
		oauthError(w, &oauth2.Error{
			Code:        oauth2.ErrorCodeAccessDenied,
			Description: "Invalid redirect URI",
		})
		return
	}

	token, secret, err := NewAccessTokenFromAuthCode(authCode)
	if err != nil {

M schema.sql => schema.sql +1 -0
@@ 36,6 36,7 @@ CREATE TABLE AuthCode (
	created_at datetime NOT NULL,
	user INTEGER NOT NULL,
	client INTEGER NOT NULL,
	redirect_uri TEXT,
	scope TEXT,
	FOREIGN KEY(user) REFERENCES User(id),
	FOREIGN KEY(client) REFERENCES Client(id)