Skip to content

Commit ce1ff4e

Browse files
authored
feat: support passkey as authentication method (#386)
* feat: support for passkey authentication Passkey is a standard that enables passwordless authentication (aka login) in the browser. It essentially defines a common API for web applications to handle passwordless technologies via FIDO2 which includes things like public key cryptography, security keys (i.e. Yubikey), and biometrics (i.e. Touch ID/Face ID, Windows Hello). In frontier config, under authentication we can add out Relaying Party details to use passkey.It takes 3 parameters, rpdisplayname, rpid, rporigins. rpdisplayname: A string representing the name or display name of the Relying Party. rpid: A string representing the ID of the Relying Party in the form of a web domain. rporigins: An array of strings specifying the allowed origins (URLs) from which authentication requests are accepted by the Relying Party. This serves as a security measure to ensure that authentication requests originate only from trusted sources. A concise explanation of the terms used: Relying Party (RP): The RP is the web application or service that handles passkey issuance and authentication. It operates both a client-side component (website or app) for creating and authenticating passkeys and a server-side component for registering, storing, and verifying passkey credentials. RP Displayname: This is the name or display name of the relying party, which is presented during the passkey authentication process. RP ID: The RP ID is the identifier for the relying party, typically in the form of a web domain. It helps ensure that passkey authentication is directed to the correct RP. RP Origins: These are the allowed origins (URLs) from which authentication requests are accepted by the RP. It's a security measure to ensure that authentication requests come from trusted sources. User Registration: In the StartFlow method, the application initially checks whether the user requires registration or login by examining the "passkey_credentials" field in the user's metadata. If present, it indicates that the user is already registered, and a login is required. If absent, user registration is necessary. To complete the registration process, the application generates a webauth credential and stores it in the User metadata under the key "passkey_credentials." User Login: In the StartFlow method, if "passkey_credentials" exists in the user's metadata, it signifies that the user is registered and can proceed with the login process. The application sets passkey user credentials and initiates the Begin Login process, which provides options and challenges for the user. Additionally, the application stores "sessionInBytes" (representing the session) and "passkey_type" (indicating login in this case) in the flow metadata. To complete the login process, the application utilizes webAuth.ValidateLogin to verify the current credentials against the stored credentials. * chore: update makefile proton commit --------- Signed-off-by: Vivek Joshi <[email protected]>
1 parent 7fbc61e commit ce1ff4e

File tree

15 files changed

+5501
-4799
lines changed

15 files changed

+5501
-4799
lines changed

Makefile

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ TAG := $(shell git rev-list --tags --max-count=1)
44
VERSION := $(shell git describe --tags ${TAG})
55
.PHONY: build check fmt lint test test-race vet test-cover-html help install proto ui
66
.DEFAULT_GOAL := build
7-
PROTON_COMMIT := "8c16ee56d3189c77eb7e677f554a1f28e8c6f53a"
7+
PROTON_COMMIT := "eb488a5599d61d8e4312ec0eb12c5065e42e3002"
88

99
ui:
1010
@echo " > generating ui build"

cmd/serve.go

+16-1
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ import (
4040
"github.com/raystack/frontier/core/authenticate/session"
4141
"github.com/raystack/frontier/core/metaschema"
4242

43+
"github.com/go-webauthn/webauthn/webauthn"
4344
"github.com/raystack/frontier/config"
4445
"github.com/raystack/frontier/core/group"
4546
"github.com/raystack/frontier/core/namespace"
@@ -229,8 +230,22 @@ func buildAPIDependencies(
229230
)
230231
logger.Info("mailer enabled", "host", cfg.App.Mailer.SMTPHost, "port", cfg.App.Mailer.SMTPPort)
231232
}
233+
234+
wconfig := &webauthn.Config{
235+
RPDisplayName: cfg.App.Authentication.PassKey.RPDisplayName,
236+
RPID: cfg.App.Authentication.PassKey.RPID,
237+
RPOrigins: cfg.App.Authentication.PassKey.RPOrigins,
238+
}
239+
webAuthConfig, err := webauthn.New(wconfig)
240+
if err != nil {
241+
if wconfig.RPDisplayName == "" && wconfig.RPID == "" && wconfig.RPOrigins == nil {
242+
webAuthConfig = nil
243+
} else {
244+
return api.Deps{}, fmt.Errorf("failed to parse passkey config: %w", err)
245+
}
246+
}
232247
authnService := authenticate.NewService(logger, cfg.App.Authentication,
233-
postgres.NewFlowRepository(logger, dbc), mailDialer, tokenService, sessionService, userService, serviceUserService)
248+
postgres.NewFlowRepository(logger, dbc), mailDialer, tokenService, sessionService, userService, serviceUserService, webAuthConfig)
234249

235250
groupRepository := postgres.NewGroupRepository(dbc)
236251
groupService := group.NewService(groupRepository, relationService, authnService, policyService)

core/authenticate/authenticate.go

+7-4
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ type AuthMethod string
1818
const (
1919
MailOTPAuthMethod = AuthMethod(strategy.MailOTPAuthMethod)
2020
MailLinkAuthMethod = AuthMethod(strategy.MailLinkAuthMethod)
21+
PassKeyAuthMethod = AuthMethod(strategy.PasskeyAuthMethod)
2122
)
2223

2324
func (m AuthMethod) String() string {
@@ -95,13 +96,15 @@ type RegistrationFinishRequest struct {
9596
Method string
9697

9798
// used for OIDC & mail otp auth strategy
98-
Code string
99-
State string
99+
Code string
100+
State string
101+
StateConfig map[string]any
100102
}
101103

102104
type RegistrationStartResponse struct {
103-
Flow *Flow
104-
State string
105+
Flow *Flow
106+
State string
107+
StateConfig map[string]any
105108
}
106109

107110
type RegistrationFinishResponse struct {

core/authenticate/config.go

+7
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ type Config struct {
1414
Token TokenConfig `yaml:"token" mapstructure:"token"`
1515
MailOTP MailOTPConfig `yaml:"mail_otp" mapstructure:"mail_otp"`
1616
MailLink MailLinkConfig `yaml:"mail_link" mapstructure:"mail_link"`
17+
PassKey PassKeyConfig `yaml:"passkey" mapstructure:"passkey"`
1718
}
1819

1920
type TokenConfig struct {
@@ -61,3 +62,9 @@ type MailLinkConfig struct {
6162
Body string `yaml:"body" mapstructure:"body" default:"Click on the following link or copy/paste the url in browser to login.<h3><a href='{{.Link}}' target='_blank'>Login</a></h3>Address: {{.Link}} <br>This link will expire in 10 minutes."`
6263
Validity time.Duration `yaml:"validity" mapstructure:"validity" default:"10m"`
6364
}
65+
66+
type PassKeyConfig struct {
67+
RPDisplayName string `yaml:"rpdisplayname"`
68+
RPID string `yaml:"rpid"`
69+
RPOrigins []string `yaml:"rporigins"`
70+
}

0 commit comments

Comments
 (0)