chadtmiller.com/knotless
git that lives in your Atmosphere account
1
10
The app's association names it for web credentials too
crates/knotless-serve/src/login.rs+2−0
| @@ -482,6 +482,8 @@ pub async fn app_association() -> Json<Value> { | ||
"components": [{ "/": APP_RETURN }], | ||
}], | ||
}, | ||
// What a browser session asks of an app it comes back to over https. | ||
"webcredentials": { "apps": [APP_ID] }, | ||
})) | ||
} | ||
| ||
crates/knotless-serve/tests/pages.rs+2−0
| @@ -351,6 +351,8 @@ fn the_app_logs_in_with_a_code_only_it_can_trade() { | ||
let details = &said["applinks"]["details"][0]; | ||
assert_eq!(details["appIDs"][0], json!("YN68LN9T7Z.dev.knotless.app")); | ||
assert_eq!(details["components"][0]["/"], json!(where_to)); | ||
let apps = &said["webcredentials"]["apps"]; | ||
assert_eq!(apps[0], json!("YN68LN9T7Z.dev.knotless.app")); | ||
| ||
// A wrong verifier spends the code, for whoever stole it. | ||
let code = code_from(&app_log_in(&server, &who.account, &challenge, "")); | ||
docs/reference/api.md+1−1
| @@ -636,7 +636,7 @@ from this site` unless its `Origin` is the site's own. | ||
| `POST /oauth/login` | `{handle, back}`: `{url}`, the PDS's page to approve on, and a `knotless_login` cookie for 15 minutes; 400 `No account answers to <handle>.`, 403 `<handle> is taken down here.` Or `{create: true, back}`: the same, the page being the sign-up page of the PDS `--sign-up-pds` names, and the account made there logged in as it comes back | | ||
| `GET /oauth/app-login?handle=&create=&challenge=` | the iOS app's login, in the browser it opens: as `POST /oauth/login`, with `challenge` a PKCE S256 challenge, but redirecting to the PDS's page rather than answering it; 400 for another length of challenge. Approved, the callback goes on to `/oauth/app-return?code=<code>`, setting no session cookie; refused, to `?error=refused` | | ||
| `GET /oauth/app-return` | a universal link the app answers; in a browser with no app, a page saying to go back to it | | ||
| `GET /.well-known/apple-app-site-association` | names the iOS app as the one that may answer `/oauth/app-return` | | ||
| `GET /.well-known/apple-app-site-association` | names the iOS app as the one that may answer `/oauth/app-return`, under `applinks`, and under `webcredentials`, which iOS asks of a browser session that comes back to an app over https | | ||
| `POST /oauth/app-token` | `{code, verifier}`: `{did, token}`, `token` the value of a `knotless_session` cookie, which the app sends as that cookie; 400 for a code unknown, spent, over five minutes old or of an account taken down, or a verifier that isn't the challenge's, which spends the code | | ||
| `GET /oauth/web-callback` | where the PDS sends the browser back: on to `back` (a path on the site, else `/`), setting `knotless_session` for 90 days if approved, and keeping the account it replaces, if any, in `knotless_accounts`; 400 for a login this browser did not start | | ||
| `POST /oauth/switch` | `{did}`: makes that account, one `knotless_accounts` holds, the one in use, keeping the one before in its place; 400 `This browser is not logged in to that account.` | | ||