feat: initial goget release — modern IPv6-first download utility
This commit is contained in:
@@ -0,0 +1,251 @@
|
||||
# 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()`.
|
||||
Reference in New Issue
Block a user