In the Medium app, if you go to the settings tab, you can change some of the settings inside the app. But, if you try to change your email notification settings, it opens up a web browser inside the app and automatically logs you in to the Medium website so that you can change your settings there.
I want to do the same thing in my Ionic React app that talks to a Drupal 8.9 server.
My Drupal site is fully functional and offers some complicated forms; my Ionic app is more limited and I don't want to re-implement everything. So if the user needs a rare or unusual feature, I want to let them open up my website (and automatically log them in) from within the app.
I use JSON:API to query the database, and Simple OAuth (OAuth2 to handle logging in.
So, I somehow need to get the Drupal session cookie when the user logs in to my site via OAuth through the Ionic app (mobile app on Android + iOS).
How can I get a session cookie to log the user in to the actual Drupal site when logging in from a decoupled app?
Desired flow
- User logs in inside the Ionic app.
- User does stuff inside the app.
- User sometimes clicks a link to my Drupal site and is still logged in to the site because I am using a Drupal session token.
The problem with OAuth is that if I click a link to a page on my Drupal site (outside my app), then I am not logged in on that page.
In my case, I really need to be able to easily redirect from inside my app to the Drupal site and stay logged in, so I want to use the Drupal session cookie for this.
Where I'm stuck is how do I get the session cookie from Drupal using Javascript?
The jsonapi documentation gives this example:
`curl --header "Content-Type: application/json" -c cookie.txt
--request POST "https://example.com/user/login?_format=json"
--data '{"mail": "t[email protected]", "pass":"password"}'`
When I do this, here's the content of cookie.txt
Netscape HTTP Cookie File
# https://curl.haxx.se/docs/http-cookies.html
# This file was generated by libcurl! Edit at your own risk.
#HttpOnly_.example.com TRUE / TRUE 1615666425 SESSf6f36d8c129ea800a6658d30964d3887 PTgk_Lgm9yLwQ3NhYtdexnexuKSJ-TItAWSkxPiUPoU
Cool, this is the drupal session cookie.
However, I only have access to Javascript, not curl, in React. Also, I'm thinking that I may be over-thinking this and there is a really simple way to get the session cookie that I have overlooked.
So, how do I get the login session cookie via Javascript?
I tried to do this with the Fetch API:
async function login(email: string, password: string): Promise<void> {
const loginPost = {
mail: email,
pass: password,
};
await fetch('https://www.example.com/user/login?_format=json', {
method: 'POST',
headers: new Headers({
Accept: 'application/json',
});
body: JSON.stringify(loginPost),
credentials: 'same-origin',
})
.then(handleErrors)
.then((response) => response.json())
.then((data) => {
const expireLate = 'Thu Nov 26 2049 15:44:38';
document.cookie = 'myJsonObject=' + JSON.stringify(data) + ';expires=' + expireLate;
})
.catch((error) => Promise.reject(new Error(error)));
}
Here's the content of the fetched cookie as shown in Chrome Dev Tools:
Name: myJsonObject
Value:
{"current_user":{"uid":"152","mail":"[email protected]"},"csrf_token":"bjaJpsNSEutjQW1BKZXxZbwaofuygF8M8vUitVvAJGo","logout_token":"27poFxhzClLA5WmYbDgql9n5v82Vc6CZBDNEztmBvb0"}
This is completely different from the session cookie I expected and that is retrieved by curl. How do I get the Drupal session cookie in a way that I can log in to my site when it is opened up in a browser from the app?
When I enter the header and request info in Postman, I get the json cookie returned by fetch api as the output, but I also get the session cookie automatically somehow. This automatic saving of the Drupal session cookie is what I want in my Ionic login form, but I don't understand enough about how Drupal handles cookies to determine how to save/retrieve the session cookie.
Background
I understand that the best practice is "use OAuth 2 or JWT; they are more secure."
In fact, the Simple Oauth module has good documentation and I managed to set this up on my site using the Drupalize.me react tutorial.
httpOnly
flag set, so it's not available from client-side javascript