Added refresh token flow

This commit is contained in:
David Allen 2024-03-18 11:05:13 -06:00
parent 6938037a3c
commit 16ec8fc422
No known key found for this signature in database
GPG key ID: 1D2A29322FBB6FCB
4 changed files with 56 additions and 2 deletions

View file

@ -24,6 +24,7 @@ type Options struct {
CachePath string `yaml:"cache"`
CacheOnly bool `yaml:"cache-only"`
TokenForwarding bool `yaml:"token-forwarding"`
Refresh bool `yaml:"refresh"`
Verbose bool `yaml:"verbose"`
}
@ -72,6 +73,7 @@ func NewConfig() Config {
FlowType: "authorization_code",
CacheOnly: false,
TokenForwarding: false,
Refresh: true,
Verbose: false,
},
Authentication: Authentication{

View file

@ -24,6 +24,7 @@ type JwtBearerFlowParams struct {
IdentityProvider *oidc.IdentityProvider
TrustedIssuer *oauth.TrustedIssuer
Client *oauth.Client
Refresh bool
Verbose bool
KeyPath string
}
@ -97,14 +98,19 @@ func NewJwtBearerFlow(eps JwtBearerEndpoints, params JwtBearerFlowParams) (strin
}
}
// add more required claims and validate
publicJwk.Set("kid", uuid.New().String())
publicJwk.Set("use", "sig")
if err := publicJwk.Validate(); err != nil {
return "", fmt.Errorf("failed to validate public JWK: %v", err)
}
trustedIssuer.PublicKey = publicJwk
// add offline_access scope to enable refresh tokens
if params.Refresh {
trustedIssuer.Scope = append(trustedIssuer.Scope, "offline_access")
}
// 3.b ...and then, add opaal's server host as a trusted issuer with JWK
if verbose {
fmt.Printf("Attempting to add issuer to authorization server...\n")
@ -131,6 +137,13 @@ func NewJwtBearerFlow(eps JwtBearerEndpoints, params JwtBearerFlowParams) (strin
payload["nbf"] = time.Now().Unix()
payload["exp"] = time.Now().Add(time.Second * 3600).Unix()
payload["sub"] = "opaal"
// include the offline_access scope if refresh tokens are enabled
if params.Refresh {
scope := payload["scp"].([]string)
scope = append(scope, "offline_access")
payload["scp"] = scope
}
payloadJson, err := json.Marshal(payload)
if err != nil {
return "", fmt.Errorf("failed to marshal payload: %v", err)

View file

@ -211,6 +211,10 @@ func (client *Client) PerformTokenGrant(clientUrl string, encodedJwt string) ([]
}
_, b, err := httpx.MakeHttpRequest(clientUrl, http.MethodPost, []byte(body), headers)
if err != nil {
return nil, fmt.Errorf("failed to make HTTP request: %v", err)
}
// set flow ID back to empty string to indicate a completed flow
client.FlowId = ""
@ -218,6 +222,18 @@ func (client *Client) PerformTokenGrant(clientUrl string, encodedJwt string) ([]
return b, err
}
func (client *Client) PerformRefreshTokenGrant(url string, refreshToken string) ([]byte, error) {
body := httpx.Body("grant_type=refresh_token" +
"&refresh_token=" + refreshToken +
"&scope" + strings.Join(client.Scope, "+"))
headers := httpx.Headers{}
_, b, err := httpx.MakeHttpRequest(url, http.MethodPost, body, headers)
if err != nil {
return nil, fmt.Errorf("failed to make HTTP request: %v", err)
}
return b, err
}
func (client *Client) DeleteOAuthClient(clientUrl string) error {
_, _, err := httpx.MakeHttpRequest(clientUrl+"/"+client.Id, http.MethodDelete, nil, nil)
if err != nil {

View file

@ -66,6 +66,29 @@ func (s *Server) Login(buttons string, provider *oidc.IdentityProvider, client *
panic(err)
}
})
r.HandleFunc("/key", func(w http.ResponseWriter, r *http.Request) {
})
r.HandleFunc("/refresh", func(w http.ResponseWriter, r *http.Request) {
// use refresh token provided to do a refresh token grant
refreshToken := r.URL.Query().Get("refresh-token")
_, err := client.PerformRefreshTokenGrant(provider.Endpoints.Token, refreshToken)
if err != nil {
fmt.Printf("failed to perform refresh token grant: %v\n", err)
http.Redirect(w, r, "/error", http.StatusInternalServerError)
return
}
// return token to target if set or the sending client
returnTarget := r.URL.Query().Get("target")
if returnTarget != "" {
} else {
host := r.URL.Host
httpx.MakeHttpRequest(host, http.MethodPost, httpx.Body{}, httpx.Headers{})
}
})
r.HandleFunc(s.Callback, func(w http.ResponseWriter, r *http.Request) {
// get the code from the OIDC provider
if r != nil {
@ -104,7 +127,7 @@ func (s *Server) Login(buttons string, provider *oidc.IdentityProvider, client *
return
}
// extract scopes from ID token and add to trusted issuer
// TODO: extract scopes from ID token and add to trusted issuer
// complete JWT bearer flow to receive access token from authorization server
// fmt.Printf("bearer: %v\n", string(bearerToken))