WebView is the old way, with some problems:
- Not a real browser (users don't see address bar), so users can't verify what they're looking at is actually the authorization server
- No shared cookies, thus worst UX. User's will have to type password everywhere (imagine login with google button)
- Even if the user is looking at the real auth server, the app can sniff passwords
Best way to do in mobile apps:
- iOS:
SFSafariViewController
- Android:
Chrome Custom Tabs
Usually with oauth we have a client_secret
but it doesn't make sense on a mobile app,
because it can be easily extracted. So using PKCE is the recommended practice nowadays.
PKCE means generating a random string, which is later SHA-256 hashed. And the hashed
string is sent at the beginning of the flow using the front-channel (expose in the url),
and the unhashed string is sent at the end, through the back-channel (doing a POST
)
For a web app it doesn't matter if you do a redirect to the oauth server again, because users barely notice the browser transition.
On mobile this means opening a pop up browser, which users will notice.
The refresh_token
is there so the application can use it behind the scenes, without
involving the user.
Sometimes the refresh_token
is returned automatically.
When it's not the scope=offline_access
must be included.
The server may have policies around which apps or even which users may get refresh_tokens.
The refresh_token
(if allowed) is received at the same time as the access_token
.
The endpoint accessed is:
POST /token
url_form_ecoded
grant_type=refresh_token&refresh_token={refresh_token}&client_id={client_id}
The refresh_token
must be securely stored.
This is taken care of by the native apps platforms, isolating apps from
each other.
Mobile OS have a secure storage API on the device. Even the app's code cannot
access it.
The refresh_token
stored in this secure storage, is accessed by prompting
the user for biometrics, which is going to unlock the secure storage and will
be accessible by the app.