You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Document public-client (PKCE) OAuth flow and CLI browser login (#1031)
DNSimple introduced a [new OAuth mechanism for the CLI](dnsimple/cli#42), along with changes to the OAuth flow itself. This updates the customer-facing developer docs to match.
On the server, the OAuth provider now supports **public clients** that authenticate with **PKCE** (RFC 7636, `S256`) instead of a `client_secret`, plus **loopback redirect URIs** with dynamic ports (RFC 8252 §7.3) for native and CLI apps. On the CLI side, `dnsimple auth login` now **defaults to an interactive browser login**, with API token login available via `--with-token`.
Related to dnsimple/dnsimple-support#1984
Install the CLI, using one of the methods below. Then run `dnsimple auth login` to login using the auth token. If you are logging into a Sandbox environment, run `dnsimple auth login --sandbox`.
22
+
Install the CLI, using one of the methods below. Then run `dnsimple auth login` to authenticate. If you are logging into a Sandbox environment, run `dnsimple auth login --sandbox`.
23
23
24
-
The CLI currently supports API token authentication, including classic and scoped API tokens.
24
+
You can authenticate in two ways:
25
+
26
+
-**Browser login** (default): run `dnsimple auth login` to authorize the CLI in your browser, with no token to copy.
27
+
-**API token**: run `dnsimple auth login --with-token` to paste or pipe a [classic or scoped API token](https://support.dnsimple.com/articles/api-access-token/).
25
28
26
29
## Installation
27
30
@@ -92,15 +95,45 @@ The command prints an AI-friendly description of available commands, flags, and
92
95
93
96
## Authentication
94
97
95
-
The CLI uses authentication contexts. A context stores the API token, account, and environment for later commands. You can keep multiple contexts, such as one for production and one for sandbox, and switch between them.
98
+
The CLI uses authentication contexts. A context stores your credential, account, and environment for later commands. You can keep multiple contexts, such as one for production and one for sandbox, and switch between them.
99
+
100
+
There are two ways to log in. Browser login is the default; API token login is available with `--with-token`. Both store the result as a context.
101
+
102
+
### Browser login
103
+
104
+
By default, `dnsimple auth login` authenticates in your browser. The CLI opens the DNSimple authorization page; once you approve, it completes the login automatically, with no token to copy or paste.
96
105
97
106
```shell
98
-
# Log in to production.
107
+
# Log in to production in the browser.
99
108
dnsimple auth login
100
109
101
-
# Log in to sandbox and store it as a separate context.
110
+
# Log in to sandbox in the browser.
102
111
dnsimple auth login --sandbox
112
+
```
113
+
114
+
Browser login uses the OAuth 2.0 Authorization Code grant with PKCE and a loopback redirect; see the [OAuth documentation](/v2/oauth/) for the underlying flow. If the CLI cannot open a browser, for example on a machine with no display server, it prints the authorization URL so you can open it manually and keeps waiting for the callback.
115
+
116
+
Browser login runs only on an interactive terminal. When standard input is not a terminal, for example a token piped in CI, `dnsimple auth login` reads an API token from stdin instead (see [Token login](#token-login)).
117
+
118
+
### Token login
119
+
120
+
To authenticate with an API token instead of the browser, pass `--with-token`. On a terminal it prompts you to paste the token, with the input hidden; with piped input it reads the token from stdin. The CLI supports classic and scoped [API tokens](https://support.dnsimple.com/articles/api-access-token/).
121
+
122
+
```shell
123
+
# Paste a token when prompted (input is hidden).
124
+
dnsimple auth login --with-token
125
+
126
+
# Pipe a token from stdin, for example in CI.
127
+
printf'%s'"$DNSIMPLE_TOKEN"| dnsimple auth login --with-token --name ci
128
+
```
129
+
130
+
You can also pipe a token to a plain `dnsimple auth login`: when standard input is not a terminal, it reads the token from stdin without `--with-token`.
103
131
132
+
### Managing contexts
133
+
134
+
List, switch, and inspect stored contexts:
135
+
136
+
```shell
104
137
# List stored contexts. The active context is marked with *.
105
138
dnsimple auth list
106
139
@@ -118,12 +151,6 @@ dnsimple auth login --name work
118
151
dnsimple auth login --sandbox --name sandbox-work
119
152
```
120
153
121
-
For scripts or machines where interactive prompts are not convenient, read a token from standard input:
122
-
123
-
```shell
124
-
printf'%s'"$DNSIMPLE_TOKEN"| dnsimple auth login --with-token --name ci
125
-
```
126
-
127
154
Remove a stored context when you no longer need it:
Copy file name to clipboardExpand all lines: content/v2/oauth.md
+36-7Lines changed: 36 additions & 7 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -12,14 +12,22 @@ excerpt: This page documents the OAuth 2 flow you can use to access the DNSimple
12
12
13
13
DNSimple supports [OAuth 2.0](http://oauth.net/) for authenticating API requests. OAuth 2 is a protocol that lets external applications request authorization to private details in a user's DNSimple account without getting their password. This is preferred over Basic Authentication because tokens can be revoked by users at any time.
14
14
15
-
Developers need to register their application before getting started. A registered OAuth application is assigned a unique client ID and client secret. The client secret should not be shared.
15
+
Developers need to register their application before getting started. A registered OAuth application is assigned a unique client ID, and the way it authenticates depends on its type:
16
+
17
+
-**Confidential clients** are server-side web apps that can keep a secret. They are assigned a client ID and a client secret, and authenticate at the token endpoint with that secret. The client secret should not be shared.
18
+
-**Public clients** are native, mobile, single-page, or command-line apps that cannot keep a secret. They authenticate with [PKCE](https://www.rfc-editor.org/rfc/rfc7636) (Proof Key for Code Exchange) instead of a client secret. See [Native and CLI apps](#native-and-cli-apps-loopback-redirect-uris).
19
+
20
+
> [!NOTE]
21
+
> If you do not see a client type choice when you register an application, your account registers web apps (confidential clients) by default. Public clients can be enabled on request; contact DNSimple support to register one for your account.
16
22
17
23
## Web Application Flow
18
24
19
25
This is a description of the OAuth 2 flow for authorizing users from 3rd party web sites. The OAuth 2 specification is described in the [RFC 6749](http://tools.ietf.org/html/rfc6749#section-4).
20
26
21
27
> [!NOTE]
22
28
> The API currently supports only the OAuth 2 [Authorization Code Grant](http://tools.ietf.org/html/rfc6749#section-4.1) flow. Therefore, [the only supported value for the `response_type` is `code`](http://tools.ietf.org/html/rfc6749#section-3.1.1).
29
+
>
30
+
> Public clients must secure the flow with [PKCE](https://www.rfc-editor.org/rfc/rfc7636) (Proof Key for Code Exchange). The only accepted `code_challenge_method` is `S256`; the `plain` method is not supported.
23
31
24
32
### Step 1 - Authorization
25
33
@@ -37,8 +45,10 @@ The following values should be passed as GET parameters:
37
45
`client_id` | **Required**. The client ID you received from DNSimple when you registered the application.
38
46
`state` | **Required**. An unguessable random string. It is used to protect against cross-site request forgery attacks and it will be passed back to your redirect URI.
39
47
`account_id` | Automatically select a preferred DNSimple account ID when the user arrives at `/oauth/authorize`. If the account is already authorized, the user will be redirected to your `redirect_uri` as a successful request.
40
-
`redirect_uri` | Where to redirect the user after authorization has completed. This must be the exact URI registered or a subdirectory.
48
+
`redirect_uri` | Where to redirect the user after authorization has completed. This must be the exact URI registered or a subdirectory. Native and CLI apps can register a [loopback redirect URI](#native-and-cli-apps-loopback-redirect-uris) whose port is matched leniently.
41
49
`scope` | We currently don't use this field.
50
+
`code_challenge` | **Required for public clients** ([PKCE](https://www.rfc-editor.org/rfc/rfc7636)). The base64url-encoded SHA-256 digest of your code verifier. Optional for confidential clients, where it adds defense-in-depth.
51
+
`code_challenge_method` | **Required when `code_challenge` is present**. Must be `S256`.
42
52
43
53
Because `/oauth/authorize` is a website, there is no direct return value. However, after the user authorizes your app, they will be sent to your redirect URI.
44
54
@@ -65,10 +75,11 @@ The following values should be passed as POST parameters:
65
75
66
76
`grant_type` | **Required**. The grant type requested. We currently only support `authorization_code`.
67
77
`client_id` | **Required**. The client ID you received from DNSimple when you registered the application.
68
-
`client_secret` | **Required**. The client secret you received from DNSimple when you registered the application.
78
+
`client_secret` | **Required for confidential clients**. The client secret you received from DNSimple when you registered the application. Ignored for public clients.
79
+
`code_verifier` | **Required for public clients** ([PKCE](https://www.rfc-editor.org/rfc/rfc7636)). The code verifier whose SHA-256 challenge matches the `code_challenge` sent to `/oauth/authorize`. Ignored for confidential clients.
69
80
`code` | **Required**. The code acquired in the previous authorization step.
70
-
`redirect_uri` | **Required**. Only used to validate that it matches the original `/oauth/authorize`, not used to redirect again.
71
-
`state` | **Required**. The state content originally passed to `/oauth/authorize`.
81
+
`redirect_uri` | **Required if it was included in the authorization request**. Only used to validate that it matches the value sent to the original `/oauth/authorize`, not used to redirect again.
82
+
`state` | **Required if it was included in the authorization request**. The state content originally passed to `/oauth/authorize`.
72
83
73
84
You'll receive a JSON response. If the request is successful, the response will include an access token, the token type and the account ID. The token type will always be `bearer`.
74
85
@@ -82,9 +93,9 @@ You'll receive a JSON response. If the request is successful, the response will
82
93
83
94
If the request fails, you'll receive a JSON response with an `error` code and an `error_description`. The HTTP status and the `error` value depend on the failure:
84
95
85
-
`invalid_grant` | **HTTP 400**. The authorization `code` is unknown or expired, or it was not issued to the supplied `client_id`.
96
+
`invalid_grant` | **HTTP 400**. The authorization `code` is unknown or expired, or it was not issued to the supplied `client_id`. For public clients, this is also returned when the PKCE `code_verifier` does not match the `code_challenge` from the authorization request.
86
97
`invalid_client` | **HTTP 401**. Client authentication failed, for example an incorrect `client_secret`.
87
-
`invalid_request` | **HTTP 400**. The request is otherwise invalid, for example an unsupported `grant_type` or a `redirect_uri` / `state` that does not match the original authorization request.
98
+
`invalid_request` | **HTTP 400**. The request is otherwise invalid, for example an unsupported `grant_type`, a `redirect_uri` / `state` that does not match the original authorization request, or a public-client authorization request with a missing or invalid PKCE `code_challenge`.
> If you are using the [sandbox environment](/sandbox/) replace `dnsimple.com` with `sandbox.dnsimple.com`.
116
+
117
+
## Native and CLI apps (loopback redirect URIs)
118
+
119
+
Native applications such as command-line tools and desktop apps are public clients: they cannot keep a client secret, so they secure the flow with [PKCE](https://www.rfc-editor.org/rfc/rfc7636) and receive the authorization `code` on a loopback callback running on the local machine.
120
+
121
+
Register a loopback callback URL as your application's redirect URI:
122
+
123
+
```
124
+
http://127.0.0.1/callback
125
+
http://[::1]/callback
126
+
```
127
+
128
+
A native app binds its callback server to an ephemeral port chosen at runtime, so it cannot register that port in advance. As described in [RFC 8252 section 7.3](https://www.rfc-editor.org/rfc/rfc8252#section-7.3), DNSimple ignores the port of a loopback redirect URI when both the registered URI and the runtime URI use a loopback IP literal. Your app can therefore listen on any available port, for example `http://127.0.0.1:53241/callback`, and the redirect URI will still match.
129
+
130
+
> [!NOTE]
131
+
> Port leniency applies only to the loopback IP literals `127.0.0.1` and `[::1]`. The hostname `localhost` is matched strictly, including its port, so use an IP literal if you need a dynamic port.
132
+
133
+
The [DNSimple CLI](/cli/) uses exactly this flow: it is a public client that runs the Authorization Code grant with PKCE and a loopback callback to log you in through your browser.
0 commit comments