tangled
alpha
login
or
join now
stream.place
/
streamplace
Live video on the AT Protocol
74
fork
atom
overview
issues
1
pulls
pipelines
oauth: add downstream authorization code
Eli Mallon
9 months ago
796f82dd
3c97efcb
+42
-25
4 changed files
expand all
collapse all
unified
split
pkg
api
oauth.go
atproto
oauth_downstream.go
oauth_upstream.go
model
oauth_session.go
+1
-1
pkg/api/oauth.go
···
262
262
q := u.Query()
263
263
q.Set("iss", "https://longos.iameli.link")
264
264
q.Set("state", upstreamSession.DownstreamPAR.State)
265
265
-
q.Set("code", "asdf")
265
265
+
q.Set("code", upstreamSession.DownstreamAuthorizationCode)
266
266
u.RawQuery = q.Encode()
267
267
http.Redirect(w, r, u.String(), http.StatusTemporaryRedirect)
268
268
}
+14
-2
pkg/atproto/oauth_downstream.go
···
54
54
return nil, fmt.Errorf("could not get oauth session: %w", err)
55
55
}
56
56
57
57
+
if session.DownstreamAuthorizationCode != tokenRequest.Code {
58
58
+
return nil, fmt.Errorf("invalid authorization code")
59
59
+
}
60
60
+
57
61
accessToken, err := generateJWT(cli, par.JKT, session.RepoDID)
58
62
if err != nil {
59
63
return nil, fmt.Errorf("could not generate access token: %w", err)
60
64
}
61
65
62
62
-
refreshToken, err := generateRefreshToken(cli)
66
66
+
refreshToken, err := generateRefreshToken()
63
67
if err != nil {
64
68
return nil, fmt.Errorf("could not generate refresh token: %w", err)
65
69
}
···
140
144
return tokenString, nil
141
145
}
142
146
143
143
-
func generateRefreshToken(cli *config.CLI) (string, error) {
147
147
+
func generateRefreshToken() (string, error) {
144
148
uu, err := uuid.NewV7()
145
149
if err != nil {
146
150
return "", err
147
151
}
148
152
return fmt.Sprintf("refresh-%s", uu.String()), nil
149
153
}
154
154
+
155
155
+
func generateAuthorizationCode() (string, error) {
156
156
+
uu, err := uuid.NewV7()
157
157
+
if err != nil {
158
158
+
return "", err
159
159
+
}
160
160
+
return fmt.Sprintf("code-%s", uu.String()), nil
161
161
+
}
+6
-2
pkg/atproto/oauth_upstream.go
···
136
136
return nil, fmt.Errorf("scope mismatch: %s != %s", itResp.Scope, meta.Scope)
137
137
}
138
138
139
139
+
downstreamCode, err := generateAuthorizationCode()
140
140
+
if err != nil {
141
141
+
return nil, fmt.Errorf("failed to generate downstream code: %w", err)
142
142
+
}
143
143
+
139
144
expiry := now.Add(time.Second * time.Duration(itResp.ExpiresIn)).UTC()
140
145
session.UpstreamAccessToken = itResp.AccessToken
141
146
session.UpstreamAccessTokenExp = expiry
142
147
session.UpstreamRefreshToken = itResp.RefreshToken
143
143
-
144
144
-
log.Log(ctx, "itResp", "itResp", itResp)
148
148
+
session.DownstreamAuthorizationCode = downstreamCode
145
149
146
150
authArgs := &oauth.XrpcAuthedRequestArgs{
147
151
Did: session.RepoDID,
+21
-20
pkg/model/oauth_session.go
···
9
9
10
10
// OAuthSession stores authentication data needed during the OAuth flow
11
11
type OAuthSession struct {
12
12
-
ID string `gorm:"primarykey"`
13
13
-
RepoDID string `gorm:"column:repo_did;index"`
14
14
-
PDSUrl string `gorm:"column:pds_url"`
15
15
-
UpstreamState string `gorm:"column:upstream_state;index"`
16
16
-
UpstreamAuthServerIssuer string `gorm:"column:upstream_auth_server_issuer"`
17
17
-
UpstreamPKCEVerifier string `gorm:"column:upstream_pkce_verifier"`
18
18
-
UpstreamDPoPNonce string `gorm:"column:upstream_dpop_nonce"`
19
19
-
UpstreamDPoPPrivateJWK []byte `gorm:"column:upstream_dpop_private_jwk;type:text"`
20
20
-
UpstreamAccessToken string `gorm:"column:upstream_access_token"`
21
21
-
UpstreamAccessTokenExp time.Time `gorm:"column:upstream_access_token_exp"`
22
22
-
UpstreamRefreshToken string `gorm:"column:upstream_refresh_token"`
23
23
-
DownstreamPARID string `gorm:"column:downstream_par_id;uniqueIndex"`
24
24
-
DownstreamPAR *PAR `gorm:"foreignKey:DownstreamPARID"`
25
25
-
DownstreamDPoPNonce string `gorm:"column:downstream_dpop_nonce"`
26
26
-
DownstreamDPoPJKT string `gorm:"column:downstream_dpop_jkt"`
27
27
-
DownstreamAccessToken string `gorm:"column:downstream_access_token;index"`
28
28
-
DownstreamRefreshToken string `gorm:"column:downstream_refresh_token;index"`
29
29
-
CreatedAt time.Time
30
30
-
UpdatedAt time.Time
31
31
-
DeletedAt gorm.DeletedAt `gorm:"index"`
12
12
+
ID string `gorm:"primarykey"`
13
13
+
RepoDID string `gorm:"column:repo_did;index"`
14
14
+
PDSUrl string `gorm:"column:pds_url"`
15
15
+
UpstreamState string `gorm:"column:upstream_state;index"`
16
16
+
UpstreamAuthServerIssuer string `gorm:"column:upstream_auth_server_issuer"`
17
17
+
UpstreamPKCEVerifier string `gorm:"column:upstream_pkce_verifier"`
18
18
+
UpstreamDPoPNonce string `gorm:"column:upstream_dpop_nonce"`
19
19
+
UpstreamDPoPPrivateJWK []byte `gorm:"column:upstream_dpop_private_jwk;type:text"`
20
20
+
UpstreamAccessToken string `gorm:"column:upstream_access_token"`
21
21
+
UpstreamAccessTokenExp time.Time `gorm:"column:upstream_access_token_exp"`
22
22
+
UpstreamRefreshToken string `gorm:"column:upstream_refresh_token"`
23
23
+
DownstreamPARID string `gorm:"column:downstream_par_id;uniqueIndex"`
24
24
+
DownstreamPAR *PAR `gorm:"foreignKey:DownstreamPARID"`
25
25
+
DownstreamDPoPNonce string `gorm:"column:downstream_dpop_nonce"`
26
26
+
DownstreamDPoPJKT string `gorm:"column:downstream_dpop_jkt"`
27
27
+
DownstreamAccessToken string `gorm:"column:downstream_access_token;index"`
28
28
+
DownstreamRefreshToken string `gorm:"column:downstream_refresh_token;index"`
29
29
+
DownstreamAuthorizationCode string `gorm:"column:downstream_authorization_code;index"`
30
30
+
CreatedAt time.Time
31
31
+
UpdatedAt time.Time
32
32
+
DeletedAt gorm.DeletedAt `gorm:"index"`
32
33
}
33
34
34
35
func (o *OAuthSession) TableName() string {