Skip to content

Instantly share code, notes, and snippets.

@sarathsp06
Created February 18, 2025 13:48
Show Gist options
  • Save sarathsp06/6e59543c249bb44bfa851e73d4b1ffa4 to your computer and use it in GitHub Desktop.
Save sarathsp06/6e59543c249bb44bfa851e73d4b1ffa4 to your computer and use it in GitHub Desktop.
OIDC cli sample
package main
import (
"context"
"crypto/rand"
"encoding/base64"
"encoding/json"
"fmt"
"log"
"net/http"
"os"
"os/exec"
"runtime"
"time"
"github.com/joho/godotenv"
"golang.org/x/oauth2"
)
type OpenIDConfig struct {
Issuer string `json:"issuer"`
AuthorizationEndpoint string `json:"authorization_endpoint"`
TokenEndpoint string `json:"token_endpoint"`
JWKSURI string `json:"jwks_uri"`
ResponseTypesSupported []string `json:"response_types_supported"`
SubjectTypesSupported []string `json:"subject_types_supported"`
IDTokenSigningAlgValues []string `json:"id_token_signing_alg_values_supported"`
}
// 1. Fetch OpenID configuration
func fetchOpenIDConfig(configURL string) (*OpenIDConfig, error) {
resp, err := http.Get(configURL)
if err != nil {
return nil, err
}
defer resp.Body.Close()
var config OpenIDConfig
if err := json.NewDecoder(resp.Body).Decode(&config); err != nil {
return nil, err
}
return &config, nil
}
// 2. Create OAuth2 config and start authentication flow
func setupAuth(config *OpenIDConfig) *oauth2.Config {
port := getEnvOrDefault("SERVER_PORT", "8089")
callbackPath := getEnvOrDefault("CALLBACK_PATH", "/lp/whole-health-rx/glp1-weightloss-questionnaire/auth/callback")
redirectURL := fmt.Sprintf("http://localhost:%s%s", port, callbackPath)
return &oauth2.Config{
ClientID: os.Getenv("OAUTH_CLIENT_ID"),
ClientSecret: os.Getenv("OAUTH_CLIENT_SECRET"),
RedirectURL: redirectURL,
Endpoint: oauth2.Endpoint{
AuthURL: config.AuthorizationEndpoint,
TokenURL: config.TokenEndpoint,
},
Scopes: []string{"openid", "offline_access"},
}
}
func generateSecureState() (string, error) {
b := make([]byte, 16)
_, err := rand.Read(b)
if err != nil {
return "", err
}
return base64.URLEncoding.EncodeToString(b), nil
}
func openBrowser(url string) error {
var cmd *exec.Cmd
switch runtime.GOOS {
case "linux":
cmd = exec.Command("xdg-open", url)
case "windows":
cmd = exec.Command("rundll32", "url.dll,FileProtocolHandler", url)
case "darwin":
cmd = exec.Command("open", url)
default:
return fmt.Errorf("unsupported platform")
}
return cmd.Start()
}
func getEnvOrDefault(key, defaultValue string) string {
value := os.Getenv(key)
if value == "" {
return defaultValue
}
return value
}
func main() {
// Load environment variables from .env file if it exists
_ = godotenv.Load()
// Fetch OpenID configuration
configURL := getEnvOrDefault("OPENID_CONFIG_URL",
"https://patient.careconnect.stg.wellsync.io/.well-known/openid-configuration")
config, err := fetchOpenIDConfig(configURL)
if err != nil {
log.Fatalf("Failed to fetch OpenID config: %v", err)
}
// Generate secure state
state, err := generateSecureState()
if err != nil {
log.Fatalf("Failed to generate state: %v", err)
}
// Setup OAuth2 config
oauth2Config := setupAuth(config)
// Start local server to handle callback
var token *oauth2.Token
var serverErr error
port := getEnvOrDefault("SERVER_PORT", "8089")
server := &http.Server{Addr: ":" + port}
callbackPath := getEnvOrDefault("CALLBACK_PATH",
"/lp/whole-health-rx/glp1-weightloss-questionnaire/auth/callback")
http.HandleFunc(callbackPath, func(w http.ResponseWriter, r *http.Request) {
if r.URL.Query().Get("state") != state {
serverErr = fmt.Errorf("state mismatch")
http.Error(w, "State mismatch", http.StatusBadRequest)
return
}
code := r.URL.Query().Get("code")
if code == "" {
serverErr = fmt.Errorf("no code returned")
http.Error(w, "No code returned", http.StatusBadRequest)
return
}
ctx := context.Background()
token, err = oauth2Config.Exchange(ctx, code)
if err != nil {
serverErr = fmt.Errorf("failed to exchange token: %v", err)
http.Error(w, "Failed to exchange token", http.StatusInternalServerError)
return
}
w.Write([]byte("Authentication successful! You can close this window."))
// Shutdown server after a short delay
go func() {
time.Sleep(100 * time.Millisecond)
server.Shutdown(ctx)
}()
})
// Start server in a goroutine
go func() {
if err := server.ListenAndServe(); err != http.ErrServerClosed {
log.Printf("HTTP server error: %v", err)
}
}()
// Get authorization URL and open browser
authURL := oauth2Config.AuthCodeURL(state, oauth2.AccessTypeOffline)
fmt.Printf("Opening browser to authenticate: %s\n", authURL)
if err := openBrowser(authURL); err != nil {
fmt.Printf("Failed to open browser. Please open this URL manually: %s\n", authURL)
}
// Wait for server to shut down
var v string
fmt.Scanln(&v)
if serverErr != nil {
log.Fatalf("Authentication failed: %v", serverErr)
}
if token == nil {
log.Fatalf("No token received")
}
// Print the token
tokenJSON, _ := json.MarshalIndent(token, "", " ")
fmt.Printf("Token received:\n%s\n", tokenJSON)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment