252 lines
6.3 KiB
Markdown
252 lines
6.3 KiB
Markdown
# 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()`.
|