···4646 RefreshToken string `json:"refresh_token"`
47474848 // Current auth server DPoP nonce
4949- DpopAuthServerNonce string `json:"dpop_authserver_nonce"`
4949+ DPoPAuthServerNonce string `json:"dpop_authserver_nonce"`
50505151 // Current host ("resource server", eg PDS) DPoP nonce
5252- DpopHostNonce string `json:"dpop_host_nonce"`
5252+ DPoPHostNonce string `json:"dpop_host_nonce"`
53535454 // The secret cryptographic key generated by the client for this specific OAuth session
5555- DpopPrivateKeyMultibase string `json:"dpop_privatekey_multibase"`
5555+ DPoPPrivateKeyMultibase string `json:"dpop_privatekey_multibase"`
56565757 // TODO: also persist access token creation time / expiration time? In context that token might not be an easily parsed JWT
5858}
···63636464 Config *ClientConfig
6565 Data *ClientSessionData
6666- DpopPrivateKey crypto.PrivateKey
6666+ DPoPPrivateKey crypto.PrivateKey
67676868 PersistSessionCallback PersistSessionCallback
6969···102102103103 var resp *http.Response
104104 for range 2 {
105105- dpopJWT, err := NewAuthDPoP("POST", sess.Data.AuthServerTokenEndpoint, sess.Data.DpopAuthServerNonce, sess.DpopPrivateKey)
105105+ dpopJWT, err := NewAuthDPoP("POST", sess.Data.AuthServerTokenEndpoint, sess.Data.DPoPAuthServerNonce, sess.DPoPPrivateKey)
106106 if err != nil {
107107 return "", err
108108 }
···121121122122 // always check if a new DPoP nonce was provided, and proactively update session data (even if there was not an explicit error)
123123 dpopNonceHdr := resp.Header.Get("DPoP-Nonce")
124124- if dpopNonceHdr != "" && dpopNonceHdr != sess.Data.DpopAuthServerNonce {
125125- sess.Data.DpopAuthServerNonce = dpopNonceHdr
124124+ if dpopNonceHdr != "" && dpopNonceHdr != sess.Data.DPoPAuthServerNonce {
125125+ sess.Data.DPoPAuthServerNonce = dpopNonceHdr
126126 }
127127128128 // check for an error condition caused by an out of date DPoP nonce
···183183 ExpiresAt: jwt.NewNumericDate(time.Now().Add(JWT_EXPIRATION_DURATION)),
184184 },
185185 }
186186- if sess.Data.DpopHostNonce != "" {
187187- claims.Nonce = &sess.Data.DpopHostNonce
186186+ if sess.Data.DPoPHostNonce != "" {
187187+ claims.Nonce = &sess.Data.DPoPHostNonce
188188 }
189189190190- keyMethod, err := keySigningMethod(sess.DpopPrivateKey)
190190+ keyMethod, err := keySigningMethod(sess.DPoPPrivateKey)
191191 if err != nil {
192192 return "", err
193193 }
194194195195 // TODO: store a copy of this JWK on the ClientSession as a private field, for efficiency
196196- pub, err := sess.DpopPrivateKey.PublicKey()
196196+ pub, err := sess.DPoPPrivateKey.PublicKey()
197197 if err != nil {
198198 return "", err
199199 }
···205205 token := jwt.NewWithClaims(keyMethod, claims)
206206 token.Header["typ"] = "dpop+jwt"
207207 token.Header["jwk"] = pubJWK
208208- return token.SignedString(sess.DpopPrivateKey)
208208+ return token.SignedString(sess.DPoPPrivateKey)
209209}
210210211211// copy a request URL and strip query params and fragment, for DPoP
···237237 sess.lk.RLock()
238238 defer sess.lk.RUnlock()
239239240240- return sess.Data.AccessToken, sess.Data.DpopHostNonce
240240+ return sess.Data.AccessToken, sess.Data.DPoPHostNonce
241241}
242242243243func (sess *ClientSession) UpdateHostDPoPNonce(ctx context.Context, nonce string) {
244244 sess.lk.Lock()
245245 defer sess.lk.Unlock()
246246247247- sess.Data.DpopHostNonce = nonce
247247+ sess.Data.DPoPHostNonce = nonce
248248249249 if sess.PersistSessionCallback != nil {
250250 sess.PersistSessionCallback(ctx, sess.Data)
+4-4
atproto/auth/oauth/types.go
···5656 TokenEndpointAuthSigningAlg *string `json:"token_endpoint_auth_signing_alg,omitempty"`
57575858 // DPoP is mandatory for all clients, so this must be present and true
5959- DpopBoundAccessTokens bool `json:"dpop_bound_access_tokens"`
5959+ DPoPBoundAccessTokens bool `json:"dpop_bound_access_tokens"`
60606161 // confidential clients must supply at least one public key in JWK format for use with JWT client authentication. Either this field or the `jwks_uri` field must be provided for confidential clients, but not both.
6262 JWKS *JWKS `json:"jwks,omitempty"`
···138138 return fmt.Errorf("%w: token_endpoint_auth_signing_alg must not be 'none'", ErrInvalidClientMetadata)
139139 }
140140141141- if !m.DpopBoundAccessTokens {
141141+ if !m.DPoPBoundAccessTokens {
142142 return fmt.Errorf("%w: dpop_bound_access_tokens must be true (DPoP is required)", ErrInvalidClientMetadata)
143143 }
144144···340340 PKCEVerifier string `json:"pkce_verifier"`
341341342342 // Server-provided DPoP nonce from auth request (PAR)
343343- DpopAuthServerNonce string `json:"dpop_authserver_nonce"`
343343+ DPoPAuthServerNonce string `json:"dpop_authserver_nonce"`
344344345345 // The secret cryptographic key generated by the client for this specific OAuth session
346346- DpopPrivateKeyMultibase string `json:"dpop_privatekey_multibase"`
346346+ DPoPPrivateKeyMultibase string `json:"dpop_privatekey_multibase"`
347347}
348348349349// The fields which are included in an initial token refresh request. These HTTP POST bodies are form-encoded, so use URL encoding syntax, not JSON.