Skip to content

Commit c6efd75

Browse files
committed
feat: use session token for API auth
Signed-off-by: Aurora Gaffney <aurora@blinklabs.io>
1 parent a42b89d commit c6efd75

12 files changed

Lines changed: 1006 additions & 460 deletions

File tree

cmd/vpn-indexer/main.go

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,19 @@ func main() {
157157
var crlInstance *crl.Crl
158158
var wgClient *wireguard.Client
159159
var s3Client *client.Client
160+
var jwtIssuer *jwt.Issuer
161+
162+
// Initialize the JWT issuer up front: it signs browser session tokens for
163+
// every protocol (so /api/auth/session is available regardless of protocol)
164+
// and also authenticates the indexer to the WireGuard container. The key
165+
// file config (VPN_JWT_KEY_FILE) is required for all protocols.
166+
jwtIssuer, err = jwt.NewIssuer(cfg.Vpn.JWTKeyFile)
167+
if err != nil {
168+
slog.Error(
169+
fmt.Sprintf("failed to initialize JWT issuer: %s", err),
170+
)
171+
os.Exit(1)
172+
}
160173

161174
switch cfg.Vpn.Protocol {
162175
case "openvpn":
@@ -181,15 +194,6 @@ func main() {
181194
// Initialize WireGuard components if protocol is wireguard
182195
slog.Info("initializing WireGuard components")
183196

184-
// Initialize JWT issuer for WG container authentication
185-
jwtIssuer, err := jwt.NewIssuer(cfg.Vpn.WGJWTKeyFile)
186-
if err != nil {
187-
slog.Error(
188-
fmt.Sprintf("failed to initialize JWT issuer: %s", err),
189-
)
190-
os.Exit(1)
191-
}
192-
193197
// Initialize WG container client
194198
wgClient = wireguard.NewClient(cfg.Vpn.WGContainerURL, jwtIssuer)
195199

@@ -252,7 +256,7 @@ func main() {
252256
}
253257

254258
// Start API listener
255-
if err := api.Start(cfg, db, caInstance, wgClient, s3Client); err != nil {
259+
if err := api.Start(cfg, db, caInstance, wgClient, s3Client, jwtIssuer); err != nil {
256260
slog.Error(
257261
"failed to start API:",
258262
"error",

docs/docs.go

Lines changed: 87 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,67 @@ const docTemplate = `{
2323
"host": "{{.Host}}",
2424
"basePath": "{{.BasePath}}",
2525
"paths": {
26+
"/api/auth/session": {
27+
"post": {
28+
"description": "Exchange a wallet-signed challenge for a short-lived session token covering all of the wallet's subscriptions",
29+
"consumes": [
30+
"application/json"
31+
],
32+
"produces": [
33+
"application/json"
34+
],
35+
"summary": "AuthSession",
36+
"parameters": [
37+
{
38+
"description": "Session Request",
39+
"name": "SessionRequest",
40+
"in": "body",
41+
"required": true,
42+
"schema": {
43+
"$ref": "#/definitions/api.SessionRequest"
44+
}
45+
}
46+
],
47+
"responses": {
48+
"200": {
49+
"description": "Session token",
50+
"schema": {
51+
"$ref": "#/definitions/api.SessionResponse"
52+
}
53+
},
54+
"400": {
55+
"description": "Bad Request",
56+
"schema": {
57+
"$ref": "#/definitions/api.ErrorResponse"
58+
}
59+
},
60+
"401": {
61+
"description": "Unauthorized",
62+
"schema": {
63+
"$ref": "#/definitions/api.ErrorResponse"
64+
}
65+
},
66+
"403": {
67+
"description": "Forbidden (no subscriptions for wallet)",
68+
"schema": {
69+
"$ref": "#/definitions/api.ErrorResponse"
70+
}
71+
},
72+
"405": {
73+
"description": "Method Not Allowed",
74+
"schema": {
75+
"type": "string"
76+
}
77+
},
78+
"500": {
79+
"description": "Server Error",
80+
"schema": {
81+
"$ref": "#/definitions/api.ErrorResponse"
82+
}
83+
}
84+
}
85+
}
86+
},
2687
"/api/client/available": {
2788
"post": {
2889
"description": "Check if a client profile is available",
@@ -690,12 +751,6 @@ const docTemplate = `{
690751
"properties": {
691752
"id": {
692753
"type": "string"
693-
},
694-
"key": {
695-
"type": "string"
696-
},
697-
"signature": {
698-
"type": "string"
699754
}
700755
}
701756
},
@@ -738,6 +793,32 @@ const docTemplate = `{
738793
}
739794
}
740795
},
796+
"api.SessionRequest": {
797+
"type": "object",
798+
"required": [
799+
"key",
800+
"signature"
801+
],
802+
"properties": {
803+
"key": {
804+
"type": "string"
805+
},
806+
"signature": {
807+
"type": "string"
808+
}
809+
}
810+
},
811+
"api.SessionResponse": {
812+
"type": "object",
813+
"properties": {
814+
"expires_at": {
815+
"type": "integer"
816+
},
817+
"token": {
818+
"type": "string"
819+
}
820+
}
821+
},
741822
"api.TxRenewRequest": {
742823
"type": "object",
743824
"properties": {
@@ -825,12 +906,6 @@ const docTemplate = `{
825906
"client_id": {
826907
"type": "string"
827908
},
828-
"key": {
829-
"type": "string"
830-
},
831-
"signature": {
832-
"type": "string"
833-
},
834909
"wg_pubkey": {
835910
"type": "string"
836911
}
@@ -866,12 +941,6 @@ const docTemplate = `{
866941
"properties": {
867942
"client_id": {
868943
"type": "string"
869-
},
870-
"key": {
871-
"type": "string"
872-
},
873-
"signature": {
874-
"type": "string"
875944
}
876945
}
877946
},
@@ -895,12 +964,6 @@ const docTemplate = `{
895964
"client_id": {
896965
"type": "string"
897966
},
898-
"key": {
899-
"type": "string"
900-
},
901-
"signature": {
902-
"type": "string"
903-
},
904967
"wg_pubkey": {
905968
"type": "string"
906969
}
@@ -912,12 +975,6 @@ const docTemplate = `{
912975
"client_id": {
913976
"type": "string"
914977
},
915-
"key": {
916-
"type": "string"
917-
},
918-
"signature": {
919-
"type": "string"
920-
},
921978
"wg_pubkey": {
922979
"type": "string"
923980
}

docs/swagger.json

Lines changed: 87 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,67 @@
1616
},
1717
"basePath": "/",
1818
"paths": {
19+
"/api/auth/session": {
20+
"post": {
21+
"description": "Exchange a wallet-signed challenge for a short-lived session token covering all of the wallet's subscriptions",
22+
"consumes": [
23+
"application/json"
24+
],
25+
"produces": [
26+
"application/json"
27+
],
28+
"summary": "AuthSession",
29+
"parameters": [
30+
{
31+
"description": "Session Request",
32+
"name": "SessionRequest",
33+
"in": "body",
34+
"required": true,
35+
"schema": {
36+
"$ref": "#/definitions/api.SessionRequest"
37+
}
38+
}
39+
],
40+
"responses": {
41+
"200": {
42+
"description": "Session token",
43+
"schema": {
44+
"$ref": "#/definitions/api.SessionResponse"
45+
}
46+
},
47+
"400": {
48+
"description": "Bad Request",
49+
"schema": {
50+
"$ref": "#/definitions/api.ErrorResponse"
51+
}
52+
},
53+
"401": {
54+
"description": "Unauthorized",
55+
"schema": {
56+
"$ref": "#/definitions/api.ErrorResponse"
57+
}
58+
},
59+
"403": {
60+
"description": "Forbidden (no subscriptions for wallet)",
61+
"schema": {
62+
"$ref": "#/definitions/api.ErrorResponse"
63+
}
64+
},
65+
"405": {
66+
"description": "Method Not Allowed",
67+
"schema": {
68+
"type": "string"
69+
}
70+
},
71+
"500": {
72+
"description": "Server Error",
73+
"schema": {
74+
"$ref": "#/definitions/api.ErrorResponse"
75+
}
76+
}
77+
}
78+
}
79+
},
1980
"/api/client/available": {
2081
"post": {
2182
"description": "Check if a client profile is available",
@@ -683,12 +744,6 @@
683744
"properties": {
684745
"id": {
685746
"type": "string"
686-
},
687-
"key": {
688-
"type": "string"
689-
},
690-
"signature": {
691-
"type": "string"
692747
}
693748
}
694749
},
@@ -731,6 +786,32 @@
731786
}
732787
}
733788
},
789+
"api.SessionRequest": {
790+
"type": "object",
791+
"required": [
792+
"key",
793+
"signature"
794+
],
795+
"properties": {
796+
"key": {
797+
"type": "string"
798+
},
799+
"signature": {
800+
"type": "string"
801+
}
802+
}
803+
},
804+
"api.SessionResponse": {
805+
"type": "object",
806+
"properties": {
807+
"expires_at": {
808+
"type": "integer"
809+
},
810+
"token": {
811+
"type": "string"
812+
}
813+
}
814+
},
734815
"api.TxRenewRequest": {
735816
"type": "object",
736817
"properties": {
@@ -818,12 +899,6 @@
818899
"client_id": {
819900
"type": "string"
820901
},
821-
"key": {
822-
"type": "string"
823-
},
824-
"signature": {
825-
"type": "string"
826-
},
827902
"wg_pubkey": {
828903
"type": "string"
829904
}
@@ -859,12 +934,6 @@
859934
"properties": {
860935
"client_id": {
861936
"type": "string"
862-
},
863-
"key": {
864-
"type": "string"
865-
},
866-
"signature": {
867-
"type": "string"
868937
}
869938
}
870939
},
@@ -888,12 +957,6 @@
888957
"client_id": {
889958
"type": "string"
890959
},
891-
"key": {
892-
"type": "string"
893-
},
894-
"signature": {
895-
"type": "string"
896-
},
897960
"wg_pubkey": {
898961
"type": "string"
899962
}
@@ -905,12 +968,6 @@
905968
"client_id": {
906969
"type": "string"
907970
},
908-
"key": {
909-
"type": "string"
910-
},
911-
"signature": {
912-
"type": "string"
913-
},
914971
"wg_pubkey": {
915972
"type": "string"
916973
}

0 commit comments

Comments
 (0)