Files

252 lines
6.3 KiB
Markdown
Raw Permalink Normal View History

# Authentication
goget supports multiple authentication mechanisms for HTTP, FTP, and SFTP connections. Credentials are resolved in priority order, with `.netrc` auto-reading as a fallback.
## Priority Order
1. CLI flags (`--username`, `--password`, `--password-file`)
2. OAuth 2.0 tokens (if configured via CLI or config)
3. `.netrc` auto-reading (`~/.netrc`)
4. Anonymous / no auth
## HTTP Basic Authentication (RFC 7617)
The simplest mechanism. Credentials are Base64-encoded in the `Authorization` header.
```bash
goget --username admin --password secret --url https://api.example.com/data
```
```
Authorization: Basic YWRtaW46c2VjcmV0
```
### Security Notes
- Basic auth sends credentials in plain text (Base64 is not encryption)
- Always use HTTPS with Basic auth
- Prefer `--password-file` for scripting to avoid credentials in shell history:
```bash
goget --username admin --password-file ./secret.txt --url https://api.example.com
```
## HTTP Digest Authentication (RFC 7616)
Digest auth never sends the password in plain text. Instead, it uses a challenge-response mechanism with MD5 or SHA-256 hashing:
```mermaid
sequenceDiagram
participant Client
participant Server
Client->>Server: GET /protected
Server-->>Client: 401 + WWW-Authenticate: Digest nonce="abc", realm="app"
Client->>Server: GET /protected + Authorization: Digest response="hash"
Server-->>Client: 200 OK
```
### Usage
```bash
goget --username admin --password secret --auth-type digest --url https://api.example.com
goget --username admin --password secret --auth-type auto --url https://api.example.com
```
With `--auth-type auto`, goget first tries to make the request. If the server returns 401 with a `WWW-Authenticate: Digest` header, it automatically switches to Digest auth.
### Implementation
The `internal/auth` package implements Digest auth per RFC 7616:
- **HA1** = `MD5(username:realm:password)`
- **HA2** = `MD5(method:digestURI)`
- **response** = `MD5(HA1:nonce:nc:cnonce:qop:HA2)`
The `cnonce` (client nonce) is generated using `crypto/rand` for each request.
## OAuth 2.0
goget supports four OAuth 2.0 grant types:
### Client Credentials Grant
For server-to-server communication without user interaction:
```bash
goget \
--oauth-client-id "my-client" \
--oauth-client-secret "my-secret" \
--oauth-token-url "https://auth.example.com/token" \
--oauth-grant-type client_credentials \
--oauth-scopes "read,write" \
--url https://api.example.com/data
```
### Authorization Code Grant
For web applications with user interaction:
```bash
# Step 1: Generate authorization URL
goget \
--oauth-client-id "my-client" \
--oauth-auth-url "https://auth.example.com/authorize" \
--oauth-redirect-uri "http://localhost:8080/callback" \
--url https://api.example.com/data
# Step 2: Exchange code for token (after user authorizes)
goget \
--oauth-client-id "my-client" \
--oauth-client-secret "my-secret" \
--oauth-token-url "https://auth.example.com/token" \
--oauth-grant-type authorization_code \
--url https://api.example.com/data
```
### Refresh Token Grant
For maintaining long-lived access:
```bash
goget \
--oauth-client-id "my-client" \
--oauth-client-secret "my-secret" \
--oauth-token-url "https://auth.example.com/token" \
--oauth-refresh-token "ref_xxx" \
--oauth-grant-type refresh_token \
--url https://api.example.com/data
```
### Token Management
```go
client := auth.NewOAuthClient(cfg)
// Check if token is valid (not expired)
if !client.IsTokenValid() {
// Refresh automatically
client.RefreshToken(ctx)
}
// Apply token to HTTP request
client.ApplyToken(httpReq)
// → Authorization: Bearer eyJhbG...
```
The token expiry is tracked with a 30-second grace period.
### Security
- **Token URL enforced to HTTPS** — plain HTTP token endpoints are rejected unless they're `localhost` or `127.0.0.1`
- **Tokens never logged** — The config `Save()` method strips `access_token`, `refresh_token`, and `client_secret` before writing to disk
## .netrc Auto-Reading
When no explicit credentials are provided via CLI flags or OAuth config, goget automatically checks `~/.netrc`:
```
machine api.example.com
login admin
password secret
machine default
login guest
password guest123
```
### Usage
```bash
# No --username or --password needed if ~/.netrc has a matching entry
goget --url https://api.example.com/data
```
### Resolution Order
1. **Exact hostname match**`api.example.com` matches `machine api.example.com`
2. **Default entry**`machine default` used as fallback
3. **No match** — proceeds without credentials
### Skip .netrc
Use `--no-private` to disable .netrc and auth file reading:
```bash
goget --no-private --url https://api.example.com
```
## Cookies
goget supports Netscape-format cookie jars:
### CLI Cookies
```bash
goget --cookie "session=abc123" --cookie "theme=dark" --url https://example.com
```
### Cookie Jar
Persist cookies across sessions:
```bash
# Save cookies to file
goget --cookie-jar cookies.txt --url https://example.com
# Load cookies from file
goget --cookie-jar cookies.txt --url https://example.com/protected
```
The cookie jar uses the standard Netscape format:
## SFTP Authentication
SFTP connections authenticate via SSH:
### SSH Key Authentication
goget auto-detects keys from standard locations:
- `~/.ssh/id_rsa`
- `~/.ssh/id_ecdsa`
- `~/.ssh/id_ed25519`
```bash
goget --url sftp://user@host:/path/to/file.zip
```
### Password Authentication
```bash
goget --url sftp://user@host:/path/to/file.zip --password "secret"
```
### Known Hosts
Host key verification uses `~/.ssh/known_hosts` by default:
```bash
# Custom known_hosts file
goget --url sftp://user@host:/path/to/file.zip --known-hosts ~/.ssh/known_hosts
# Skip verification (first connection)
goget --url sftp://user@host:/path/to/file.zip --ssh-insecure
```
## FTP Authentication
FTP connections default to anonymous login. For authenticated FTP:
```bash
# Username/password
goget --url ftp://ftp.example.com/file.zip --username user --password pass
# Anonymous (default)
goget --url ftp://anonymous@ftp.example.com/file.zip
```
## Access Tokens in URLs
While `https://user:pass@example.com` URLs are supported, prefer `--username` and `--password` CLI flags. When a URL contains credentials, they're automatically stripped from error messages and logs via `core.SafeURL()`.