mirror of
https://github.com/davidallendj/opaal.git
synced 2025-12-20 03:27:02 -07:00
Added refresh token flow
This commit is contained in:
parent
6938037a3c
commit
16ec8fc422
4 changed files with 56 additions and 2 deletions
|
|
@ -24,6 +24,7 @@ type Options struct {
|
||||||
CachePath string `yaml:"cache"`
|
CachePath string `yaml:"cache"`
|
||||||
CacheOnly bool `yaml:"cache-only"`
|
CacheOnly bool `yaml:"cache-only"`
|
||||||
TokenForwarding bool `yaml:"token-forwarding"`
|
TokenForwarding bool `yaml:"token-forwarding"`
|
||||||
|
Refresh bool `yaml:"refresh"`
|
||||||
Verbose bool `yaml:"verbose"`
|
Verbose bool `yaml:"verbose"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -72,6 +73,7 @@ func NewConfig() Config {
|
||||||
FlowType: "authorization_code",
|
FlowType: "authorization_code",
|
||||||
CacheOnly: false,
|
CacheOnly: false,
|
||||||
TokenForwarding: false,
|
TokenForwarding: false,
|
||||||
|
Refresh: true,
|
||||||
Verbose: false,
|
Verbose: false,
|
||||||
},
|
},
|
||||||
Authentication: Authentication{
|
Authentication: Authentication{
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@ type JwtBearerFlowParams struct {
|
||||||
IdentityProvider *oidc.IdentityProvider
|
IdentityProvider *oidc.IdentityProvider
|
||||||
TrustedIssuer *oauth.TrustedIssuer
|
TrustedIssuer *oauth.TrustedIssuer
|
||||||
Client *oauth.Client
|
Client *oauth.Client
|
||||||
|
Refresh bool
|
||||||
Verbose bool
|
Verbose bool
|
||||||
KeyPath string
|
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("kid", uuid.New().String())
|
||||||
publicJwk.Set("use", "sig")
|
publicJwk.Set("use", "sig")
|
||||||
|
|
||||||
if err := publicJwk.Validate(); err != nil {
|
if err := publicJwk.Validate(); err != nil {
|
||||||
return "", fmt.Errorf("failed to validate public JWK: %v", err)
|
return "", fmt.Errorf("failed to validate public JWK: %v", err)
|
||||||
}
|
}
|
||||||
trustedIssuer.PublicKey = publicJwk
|
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
|
// 3.b ...and then, add opaal's server host as a trusted issuer with JWK
|
||||||
if verbose {
|
if verbose {
|
||||||
fmt.Printf("Attempting to add issuer to authorization server...\n")
|
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["nbf"] = time.Now().Unix()
|
||||||
payload["exp"] = time.Now().Add(time.Second * 3600).Unix()
|
payload["exp"] = time.Now().Add(time.Second * 3600).Unix()
|
||||||
payload["sub"] = "opaal"
|
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)
|
payloadJson, err := json.Marshal(payload)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("failed to marshal payload: %v", err)
|
return "", fmt.Errorf("failed to marshal payload: %v", err)
|
||||||
|
|
|
||||||
|
|
@ -211,6 +211,10 @@ func (client *Client) PerformTokenGrant(clientUrl string, encodedJwt string) ([]
|
||||||
}
|
}
|
||||||
|
|
||||||
_, b, err := httpx.MakeHttpRequest(clientUrl, http.MethodPost, []byte(body), headers)
|
_, 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
|
// set flow ID back to empty string to indicate a completed flow
|
||||||
client.FlowId = ""
|
client.FlowId = ""
|
||||||
|
|
@ -218,6 +222,18 @@ func (client *Client) PerformTokenGrant(clientUrl string, encodedJwt string) ([]
|
||||||
return b, err
|
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 {
|
func (client *Client) DeleteOAuthClient(clientUrl string) error {
|
||||||
_, _, err := httpx.MakeHttpRequest(clientUrl+"/"+client.Id, http.MethodDelete, nil, nil)
|
_, _, err := httpx.MakeHttpRequest(clientUrl+"/"+client.Id, http.MethodDelete, nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
||||||
|
|
@ -66,6 +66,29 @@ func (s *Server) Login(buttons string, provider *oidc.IdentityProvider, client *
|
||||||
panic(err)
|
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) {
|
r.HandleFunc(s.Callback, func(w http.ResponseWriter, r *http.Request) {
|
||||||
// get the code from the OIDC provider
|
// get the code from the OIDC provider
|
||||||
if r != nil {
|
if r != nil {
|
||||||
|
|
@ -104,7 +127,7 @@ func (s *Server) Login(buttons string, provider *oidc.IdentityProvider, client *
|
||||||
return
|
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
|
// complete JWT bearer flow to receive access token from authorization server
|
||||||
// fmt.Printf("bearer: %v\n", string(bearerToken))
|
// fmt.Printf("bearer: %v\n", string(bearerToken))
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue