96 lines
3.2 KiB
Go
96 lines
3.2 KiB
Go
package auth
|
||
|
||
import (
|
||
"net/http"
|
||
"net/url"
|
||
|
||
"github.com/google/go-querystring/query"
|
||
)
|
||
|
||
type AuthorizeParams struct {
|
||
// A string-encoded JSON object that specifies the claims to include in the ID token.
|
||
// For information about claims, see Requesting claims: https://dev.twitch.tv/docs/authentication/getting-tokens-oidc/#requesting-claims
|
||
//
|
||
// Only used for OIDC auth flows
|
||
Claims *Claims `url:"claims,omitempty"`
|
||
|
||
// Set to true to force the user to re-authorize your app’s access to their resources.
|
||
// The default is false.
|
||
ForceVerify *bool `url:"force_verify,omitempty"`
|
||
|
||
// Although optional, you are strongly encouraged to pass a nonce string to help
|
||
// prevent Cross-Site Request Forgery (CSRF) attacks. The server returns this string
|
||
// to you in the ID token’s list of claims. If this string doesn’t match the nonce
|
||
// string that you passed, ignore the response. The nonce string should be randomly
|
||
// generated and unique for each OAuth request.
|
||
//
|
||
// Only used for OIDC auth flows
|
||
Nonce *string `url:"nonce,omitempty"`
|
||
|
||
// Must be set to code for Authorization code grant flow.
|
||
// Recommended for Server-to-Server flows. (with backend)
|
||
//
|
||
// Must be set to token for Implicit grant flow.
|
||
// Recommended for Client-to-Server flows. (no backend)
|
||
ResponseType string `url:"response_type"`
|
||
|
||
// A space-delimited list of scopes. The APIs that you’re calling identify the
|
||
// scopes you must list. The list must include the openid scope. Don’t forget to
|
||
// URL encode the list.
|
||
Scope []Scope `url:"scope,space"`
|
||
|
||
// Although optional, you are strongly encouraged to pass a state string to help
|
||
// prevent Cross-Site Request Forgery (CSRF) attacks. The server returns this string
|
||
// to you in your redirect URI (see the state parameter in the fragment portion of
|
||
// the URI). If this string doesn’t match the state string that you passed, ignore
|
||
// the response. The state string should be randomly generated and unique for each
|
||
// OAuth request.
|
||
State *string `url:"state,omitempty"`
|
||
}
|
||
|
||
const AuthorizeUrl = "https://id.twitch.tv/oauth2/authorize"
|
||
|
||
// AuthorizeUrl returns the URL to redirect the user to for authorization.
|
||
func (c *Client) AuthorizeUrl(params *AuthorizeParams) *url.URL {
|
||
v, _ := query.Values(params)
|
||
v.Set("client_id", c.clientId)
|
||
v.Set("redirect_uri", c.redirectUri)
|
||
url, _ := url.Parse(AuthorizeUrl)
|
||
url.RawQuery = v.Encode()
|
||
return url
|
||
}
|
||
|
||
type AuthorizeHandler struct {
|
||
client *Client
|
||
scopes []Scope
|
||
}
|
||
|
||
var _ http.Handler = (*AuthorizeHandler)(nil)
|
||
|
||
// AuthorizeHandler returns an http.Handler that redirects the user to the
|
||
// authorization URL.
|
||
func (c *Client) AuthorizeHandler(scopes []Scope) http.Handler {
|
||
return &AuthorizeHandler{
|
||
client: c,
|
||
scopes: scopes,
|
||
}
|
||
}
|
||
|
||
// ServeHTTP implements http.Handler.
|
||
func (h *AuthorizeHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||
state := GenerateState()
|
||
|
||
if err := h.client.stateStorage.Save(w, state); err != nil {
|
||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||
return
|
||
}
|
||
|
||
url := h.client.AuthorizeUrl(&AuthorizeParams{
|
||
ResponseType: "code",
|
||
Scope: h.scopes,
|
||
State: &state,
|
||
})
|
||
|
||
http.Redirect(w, r, url.String(), http.StatusFound)
|
||
}
|