Leveraging Weka Library for Facebook Data Analysis

Weka (Waikato Environment for Knowledge Analysis) is a popular suite of machine learning software written in Java, developed at the University of Waikato, New Zealand. It is an open-source library that provides a collection of machine-learning algorithms for data mining tasks. In this article, we will explore how to use the Weka library to analyze Facebook data to gain insights into user behavior and preferences. We will walk through a real-world use case and provide code examples to help you get started with Weka.

Use Case: Analyzing Facebook User Likes and Interests

In this use case, we will analyze a dataset containing information about Facebook users, their likes, and interests. Our goal is to identify patterns and trends in user behavior and preferences, which can be used for targeted advertising or improving user experience on the platform.

Understanding Authentication In Websites: A Banking Analogy

There is a strange ritual that web developers around the world have been perpetuating from the dawn of computers to modern days. Without this ritual, the web application cannot really exist. It is not “ready to go live,” a web developer would say. This ritual is the implementation of authentication.

You may have been through this ritual multiple times. But do you really understand what is happening?

This article is my attempt at making this ritual less obscure. It shouldn’t have to take a wizard to implement a good authentication system. Just a good banker!

Your Password Matched. Now What?

Authentication is the process of attributing a given request to a unique entity, usually a person. It then enables authorization, the process of allowing (or not) said person to access a resource, be it a web page or an API endpoint.

I will focus on the part I’ve always found the most difficult to understand: what happens after the user just submitted the login form and their credentials were confirmed as valid by the backend.

  app.post("/login", async (request, response) => {
    const { body } = request;
    const user = await getUserByCredentials(body.username, body.password);
    if (user) {
      // NOW WHAT???
    }

Your typical login endpoint. This article is about what happens afterward.

We are going to talk about tokens, CORS, cookies, and headers. Those concepts are sometimes quite abstract. To make them more real, I’ll take a shot at a banking analogy.

Authentication Relies On Tokens Like Banks Rely On Money

Let’s consider two common patterns:

  • JSON Web Tokens aka JWT.
    It’s an open standard. You’ll find useful resources at the bottom of this article if you want to go further.
  • Session-based authentication.
    It’s a pattern more than a standard. So the implementation may vary, but I’ll try to give an overview of how it works.

As a front-end developer, you may have no control over this design decision, so it’s important that you understand how both work.

As a full-stack or backend developer, you have control over this choice, so it’s even more important that you understand what you are doing. I mean, it’s kinda your job :)

A JWT Is Like A Banknote

With JSON Web Token-based authentication (JWT), during the login step, the server will pass the client a token that contains encrypted information, a “claim.” When the client makes a request, they pass this token alongside the request.

The server verifies that this token is indeed a valid token that it itself generated earlier. Then the server reads the token payload to tell who you are, based on a user ID, username, email, or whatever the payload is. Finally, it can authorize or refuse access to the resource.

Think of tokens as banknotes. A banker can print new banknotes like a server can create tokens. Money lets you buy things, or if I rephrase, it lets you access paid goods and services. The JWT lets you access secure services the same way.

If you want to use your money, either at the bank to credit your account or in a store, people will double-check that your banknotes are real. A real banknote is one that has been created by the bank itself. When the banknote is confirmed to be legit, they can read the value on it to tell how many things you can buy.

JWTs work the same, the server can verify that they indeed created this token earlier, so it’s a real one, and then they can read the payload it contains to confirm who you are and what your permissions are.

Revoking a token can be hard. The server has to maintain a list of blacklisted tokens that are no longer valid, like the bank would need to list robbed banknotes’ unique numbers.

Session-Based Authentication Is Like A Credit Card

From the front-end developer standpoint, the main difference between JWT and session-based authentication lies in what the server will return in case of a successful login.

In session-based authentication, instead of having a claim full of user information, you just get a “session id.”

From the backend developer’s standpoint, session-based authentication involves an additional database collection or table to store the sessions. A session is just an object very similar to the JWT, which can contain, for instance, a user id and an expiration date.

This means that the server keeps a lot of control over the authentication. It can log a user out by removing the session from the database, whereas it cannot destroy JWTs, since it doesn’t store them.

Session-based authentication is comparable to credit cards. You go to the bank to open your account. The banker will check your id and issue a credit card with an expiration date. This is the authentication process.

The credit card itself has barely any value: it’s just plastic and a microchip whose purpose is to uniquely identify your account. It can easily be revoked by the bank, usually after a certain period of time, but also when you declare your card stolen.

When you want to pay for something, the store will communicate with your bank to check that your credit card is valid and has a positive balance.

When you access an authenticated resource, the server will check if the session id matches an open session and then if this session matches a user that is authorized to access this resource.

Tokens Are As Precious As Banknotes And Credit Cards. Don’t Get Them Stolen!

It’s easy for companies and banks to store money. They have those big reinforced-steel safes with alarms and sometimes even dragons. Likewise, it’s easy for servers to talk securely to one another.

But websites are like private persons. They can’t have dragons, so they have to imagine specific approaches to store their precious tokens.

Where Do You Store Your Money?

Whatever the pattern you pick to authenticate users, JSON web tokens and session ids are precious things. In the remainder of this article, I will treat them similarly, apart from a few technical subtleties. I’ll call either of them the “authentication token,” the thing you show the server to prove that you are authenticated, like money for paying stuff.

Since you have to pass the token alongside every request you make to the server — you need to store it somewhere on the client side.

Here, I’d like to focus more specifically on the case of websites, where the web browser is in charge of sending the requests. You’ll find many articles and documentation in the wild that do not clarify whether they apply to server-server communication or browser-server. The latter is a trickier, uncontrolled context that deserves its own specific patterns.

So, the banker just handed you either a new credit card or a bunch of banknotes. Where do you stash them? In a compartment concealed in the heel of your shoe, in your mailbox, beneath your mattress, or maybe, in your fancy fanny pack?

Not All Requests Are Born Equal: Loading A Web Page vs. Calling An API

We can divide authenticated content into two categories: web pages and API endpoints. From a technical standpoint, both are server endpoints. The former returns HTML content or files, the latter — any kind of content, often JSON data. They differ in the way they are consumed.

Web pages are accessed via a web browser that triggers GET requests automatically, depending on the current URL.

APIs are called using JavaScript code. This reliance on APIs and JavaScript is at the core of the Jamstack, REST, and Single-Page-Application philosophies.

Thus, let’s differentiate two use cases:

  1. You want to secure access to the web page itself. Meaning the user can’t even see the structure of your page or any HTML.
  2. You want to secure calls from your web page to your API. Anyone can see your web page structure, but they can’t get any data.

If you combine both, unauthenticated users can’t see the page structure and can’t get any data from your API.

Use Case 1: Securing A Web Page Access With Cookies

I’ll cut it short, to secure web page access, you have no other choice but to use cookies, ideally HTTP-Only, secure cookies.

From a technical standpoint, a cookie is a piece of data that should be sent alongside every request to a specific domain. They are part of the HTTP protocol.

That’s a pretty broad scope. When a website cookie popup differentiates “essential cookies” from other cookies, those essential cookies are often dedicated to authentication. The others are just a way to keep track of the product pages you’ve visited to later shove them in your face to the point of literally optimizing the billboard displays in your neighborhood as if you really, really wanted to buy two freezers within the same month.

Setting a cookie is possible in both directions. Client-side JavaScript can set cookies to be sent to the server. That’s how advertisement tracking works (though GDPR is forcing advertisers to use server-side logic more and more these days).

But the server can also tell the browser to store a cookie using the Set-Cookie header in the response.

This convenient feature lets the backend set what we call “HTTP-only” cookies: cookies that cannot be read by JavaScript. And “secure” cookies are only set through HTTPS for better security.

Important note: Using HTTP-only cookies prevents XSS attacks (script injection to steal the token) but not CSRF attacks (forging requests on behalf of your authenticated users, basically impersonating them). You need to combine multiple strategies to parry all possible attacks. I invite you to read more on these topics if you manage a non-trivial website.

During the authentication process, the Set-Cookie header should be used in response to the “login” request so the client becomes authenticated via a token.

Cookies are like a wallet. You can store fidelity cards in it and a picture of your cat, but also duller things, like your money. It’s in your pocket or your handbag, so it’s hard to access for other people (HTTP-only, no JavaScript access) if you don’t take it out in unsafe places (secure). Yet, you always have your token with you if needed.

Browsers rely a lot on cookies, and they send them automatically alongside every request they trigger as long as the domain and path match, so you don’t have to worry about them. If you carry your wallet with you anytime you go out, you’re always ready to pay.

Use Case 2: Securing API Calls. The Cookie Scenario

Now, let’s authenticate calls to our API, which feeds the website with data. The easiest option would be to use a cookie, as we did in the previous section, to secure web pages. But contrary to the web page, there is also another option — using web storage. Which one is the most suited is debatable. Let me start with cookies.

The cookie that contains the auth token is sent automatically alongside requests triggered by the browser when you navigate a website or when you submit a form.

But requests triggered by JavaScript code do not fall into this category. When you trigger a request programmatically, you need a bit more configuration to send cookies.

Remember that the cookie should be HTTP-only, so you can’t read the cookie content with JavaScript nor inject your token in the Authorization header. You could do that with a cookie that is not HTTP-only, but then using a cookie doesn’t make sense in the first place.

All existing libraries capable of sending requests have to be based on the browser JavaScript API aka the “Browser Object Model,” which means either XMLHttpRequest or fetch. You have to rely on their configuration to enable sending HTTP-only cookies alongside the request.

In the case of fetch, this option is named credentials. Hopefully, for you, fellow front-end developers, it’s very easy to use.

fetch(
"http://localhost:8000/account/signup", 
{ 
  method: "POST",
  body: JSON.stringify({username:"foo", password:"barbar"}), 
  // This will include credentials (here, cookies) in the request
  credentials: "include"
})

With XHR, the option is named withCredentials and behaves similarly.

Note: Your server must also confirm that it indeed accepts credentials by setting the Access-Control-Allow-Credentials header to true in the responses. This option is symmetrical. It controls both sending cookies to the server, but also accepting the Set-Cookie header from it. So don’t forget to set it to true for the call to the login endpoint.

If the credentials option is not set and the server answers with a Set-Cookie header… the browser will silently ignore this attempt to set the cookie without even a warning. When this happens, start by double-checking your credentials option and then CORS if applicable (see next section).

Oops, I’ve almost forgotten your banking analogy! It’s a tough one but let’s say that you probably have your credit card or a few banknotes always there in your wallet. But some services expect a prepaid card, and you may need to explicitly remember to take them with you. That’s the best analogy I could achieve. Comment if you can do better!

Return Of Use Case 2: Securing API Calls. The Web Storage Scenario

Remember, I said earlier that for API calls, you have the choice to either store the token in an HTTP-only cookie, like you would do to secure a web page, or to store the token in the web storage. By web storage, we mean either sessionStorage or localStorage.

I’ve seen and used both approaches, cookies and web storage, but I sincerely don’t have the expertise to assert that one is better than the other. I’ll stick to describing how it works so you can make an enlightened decision.

Codewise, they are much easier to use than HTTP-only cookies because web storage is available to JavaScript code. You can get the token from the login response payload, store it in localStorage, and insert it into the Authorization header in later requests. You have full control of the process without relying on some implicit browser behavior.

headers: {
    “Authorization”: `Bearer ${window.localStorage.get(“auth_token”)}`
}

Web storage is immune to certain attacks, namely Cross-Site Request Forgery. That’s because, contrary to cookies, they are not automatically tied to requests, so an attacker will have trouble forcing you to give your token. Think of a piggy bank. You can’t just get money out of it. It’s, however, very sensitive to script injection, where an attacker manages to run JavaScript and reads the token.

Therefore, if you go the web storage way, you’ll want to explore strategies that prevent XSS attacks from happening in the first place.

JWT Specifics: What Information They Should Contain And How To Handle The Refresh Token

You should avoid storing critical information in a JSON web token, even when using HTTP-only cookies. If someone still manages to steal and decrypt the token, they will be able to impersonate the user, but at least they won’t be able to get much information from the token itself.

You can afford to lose a five-dollar banknote; it’s more problematic to lose a $5,000 banknote. By the way, if such a thing as a $5,000 banknote exists, please send me a specimen to prove it. Thank you.

JWTs are meant to be short-lived, like banknotes, which would wear quickly when used a lot. Since they are hard to revoke, giving them 5-minute lifetime guarantees that even a stolen JWT token cannot be a big problem.

Since you don’t want the user to log in again every 5 minutes, the token can be combined with a longer-lived refresh token. This second token can be used to get a new JWT.

A best practice is to store the refresh token in a cookie on a very specific path like /refresh (so it’s not sent with all requests, contrary to the JWT) and to make it a one-time-only token.

A refresh token is like bringing your ID card to get more money from your bank account. You don’t do that often, and you probably want to store your ID even more safely than your banknotes.

CORS Is How Shops Communicate With Their Bank

Formally, CORS (Cross-Origin Resource Sharing) is a protocol used by servers in order to instruct browsers to selectively relax some of the Same-Origin Policy (SOP) restrictions on network access for some trusted clients.

Less formally, the server can tell your browser that the request you send is legit based on the request’s origin. If the server says it’s not legit, the browser won’t send the request.

For instance, https://www.foobar.com, https://qarzed.fake, and http://localhost:8080 are possible origins. The port and protocol matter.

An API hosted on https://api.foobar.com will most often allow requests only from https://www.foobar.com and https://mobile.foobar.com.

I will focus here on API calls triggered with fetch in JavaScript, and only if the API lives in another Web origin. CORS also affects more advanced use cases like embedding images from another website in your own website, iframe, navigating from one site to another, and so on, but that’s beyond the scope of authentication per se.

Websites are like stores. People can enter them and try to buy things. But the store also has its own complicated internal back office logic. Namely, it relies on a bank to process payments.

Any shop owner can try to connect to any bank. Any website can try to connect to any API. But the payment won’t be processed by the bank if they don’t have a company account there.

Likewise, if you host the website on www.foobar.com and the API on www.foobar.com/api, there is one origin only www.foobar.com. No need for CORS because there is no “cross-origin” call involved. You’ll need to bother about CORS if, instead, you host the API on api.foobar.com. We have two distinct origins, api.foobar.com and www.foobar.com.

This also applies to using different ports on localhost during development. The IP 127.0.0.1 is even different from localhost, as origins are compared directly as strings and not based on their actual IP address.

Some big companies, like car sellers, have their own internal bank. It’s easier for them to communicate with this bank if it’s literally located in the same office. They are like full-stack monolithic applications.

But if this internal bank is located in a different country (API separate from the website), this doesn’t work anymore. It could as well be a traditional bank with multiple clients (a third-party API). CORS is needed either way.

CORS is a concept specific to browser-server communication. When a server talks to another server, the Same-Origin Policy doesn’t apply. The API may either block those requests with no origin completely or, on the contrary, accept them, or filter them based on IP and so on.

Banks have specific patterns of communicating with each other that are different from how they communicate with their client companies.

A Polite Cross-origin Discussion Between A Server And A Client, Using Preflight Requests

Here’s a more concrete vision of what happens during a cross-origin request and how the server response headers should be set.

From the browser standpoint, whenever a website sends a “non-simple” request to an API, the browser will first send a preflight request. It’s a request to the same URL but using the OPTIONS method, which is dedicated to checking whether you can actually consume this API endpoint.

Fetching JSON data falls into this “non-simple” category in standard browsers, as well as calling your login endpoint if the auth API doesn’t live on the same domain as your website, so this step is extremely important.

The server receives this request, which includes an Origin header. It checks its own list of accepted origins. If the origin is allowed, it will respond with the right Access-Control-Allow-Origin header.

This server header should match the website’s origin. It can also be a wildcard * if the API is totally open, but that works only for requests without credentials, so forget about this if your API requires authentication.

If the response header doesn’t match, the browser will trigger an error at this point because they already know that they can’t call this API. Otherwise, they will keep going and send the actual request.

A store (the API) can decide to accept only certain types of credit cards. Some stores accept only their own card, and they don’t even use CORS (same-origin scenario). Some stores accept only Visa or Mastercards (cross-origin scenario). The cashier (the browser) won’t let you pay if they are told your card is not accepted by the store.

There are a few other Access-Control headers that provide more information, like accepted methods or headers. Allow-Origin is the most basic one, as well as Allow-Credentials, so cookies and Set-Cookie headers are properly enabled when using fetch.

Access-control-allow-origin: https://www.foobar.com
Access-control-allow-credentials: true

Expected response headers for an authenticated call (or the “login” form submission) if the website lives on https://www.foobar.com and the API is on another domain or port.

Note: The server specifies the CORS policy, and the browser enforces it. If suddenly everyone used an unsafe browser run by pirates, they could swarm your server with forged requests. Hopefully, people usually don’t use a shady browser they found in a USB key itself found lying on the ground of a dark alley at 3 am.

The header things and the browser behavior are just politeness. The browser is an excessively polite software. It will never spam the server with requests that will be rejected anyway. And it won’t talk to rude servers that don’t set the proper headers. That’s why the Accept-Control-Allow-Origin response header must be correctly set for cross-origin requests to work.

Before going as far as aiming a customer with a shotgun, the banker will probably tell you, “sir, you entered the wrong bank office,” and the customer will probably answer, “oh, sorry, my mistake. I will leave immediately!”.

Cookies Or Not Cookies: The SameSite Option

Setting the credentials attribute in your fetch request is not enough for sending the cookie, plus it doesn’t apply to pages, only to programmatic requests. The SameSite attribute of cookies lets you configure when a cookie should be sent, depending on the current site.

The concept of “Site” is slightly different from the concept of domain:

  • https://api.foobar.com and https://www.foobar.com are 2 different domains.
  • They are, however, the same site. Nowadays, the scheme matters, too (HTTP vs. HTTPS).
  • There is an exception to this rule, e.g., in multi-tenant architectures: foo.github.io and bar.github.io will be different sites despite having the same domain, and the server owner can configure that to their will.

If the Access-control response headers are correctly set, and the preflight request succeeds, the browser will proceed with the actual request.

But if SameSite is not set with the right value in the cookie containing the authentication token, this cookie won’t be sent to the server. When loading a page, you will be considered unauthenticated by the server just because it literally doesn’t have your cookie.

The SameSite: Lax value is usually the most appropriate. It will only send cookies to the same site but also when the user comes from another site and is redirected to your page (only for top-level navigations). This is the current default in most browsers.

With SameSite: Lax, the website www.foobar.com will automatically include the authentication cookie when it sends requests to api.foobar.com, which is part of the same site. Authentication will work as expected.

Sec-Fetch Helps Detecting Cross-origin Requests But Are Not Standard Yet

Related to CORS, you may also hear about the Sec-Fetch request headers. They provide information about the request context to the server. For instance, if Sec-Fetch-Site is same-origin, there is no need to check the Origin header. It’s slightly more intuitive than manually checking the request origin against predefined rules. If it’s same-site, you still need to add the required CORS headers in the response because the site and the origin are different concepts.

However, those headers are not sent by all browsers. Namely, Safari doesn’t support them at the time of writing. Therefore, they can only act as a secondary solution to identify a request’s origin.

A bank can identify you via your passport, but not everybody has a passport, so you will always need to resort to a good old ID card. Passports are still a cool way to identify people when available. That’s what the Sec-Fetch headers are.

Keep in mind that attackers may trick users into sending requests they don’t want to, but they still have no control over which browser will send the request. Thus, Sec-Fetch headers are still useful despite being supported only by some browsers. When they are present, they are a reliable piece of information.

More broadly, cross-origin and cross-site security patterns are based on the fact that users are using legitimate browsers that should never try to voluntarily mislead servers about the origin. Beware of more elaborate attacks, such as subdomain takeover, that can still bypass these security measures.

You may think, what about servers, then? Server requests are able to spoof a request origin, effectively bypassing CORS. Well, that’s right: CORS is a browser-server security mechanism; it simply doesn’t apply to server-server calls. Someone can build an API that calls your own API and serve the result to another website. True.

However, the thief will have to host a server, which isn’t free, so they will pay actual money for this API call, and the server IP may be traced back to them. It’s way less attractive than forcing browsers to send the request directly to your API, which would be free and trace back to the first victim, your user, and not to the attacker. Thanks to CORS, this worst-case scenario is not possible.

No, We Don’t Take Checks: Don’t Confuse A Web Page Access And An API Call

If you’ve stumbled upon this article, you have probably read a lot of documentation before that. You might have encountered various patterns that seem very different from one another and may be very different from what I’ve been describing so far.

I’d like to point out that this article is about authentication for websites. This is, I believe, the root of all confusion. First, the requests are sent by a browser, not by another server. Then, a page of a website can be accessed via the URL bar, and the website can send calls to an API via JavaScript; that’s two very different situations.

We have detailed the technical differences between each scenario earlier in this article. But let’s recap again to better understand the most common sources of confusion.

Using Browser Storage (Session, Local, And Friend) Is Like Using Your Mailbox As A Piggy Bank

Setting your token in localStorage is like storing money in your physical mailbox. Well, technically, it’s safe. It’s even used to temporarily store your mail. Session storage is similar; it’s just like getting your mail every day instead of letting it rot for weeks. Be nice to the postman!

But either way, the storage is accessible to JavaScript. It’s not open like your mailbox most probably has a lock. But it’s still lying outside.

Someone who is really mean could craft a key and go as far as discreetly stealing your mail for days. That’s what would happen to your users if someone manages to run a script injection attack in your application. They can craft a JS script that reads the localStorage, and sends them the tokens of any of your users affected by the breach!

There are ways to prevent cross-scripting attacks. It’s not a fatality, and some would argue that it’s still better than using an HTTP-only cookie! But if you go the web storage way, don’t forget to protect your mailbox.

JWTs Passed As Header: It’s A Pattern For API Calls Only

I’d like to go one step further and understand why so many developers are tempted to use the browser storage without even considering the cookie option.

I think there are two main reasons:

  1. The API doesn’t use Set-Cookie during the login step. It often happens in APIs that were not specifically designed to be accessed from a browser, and they use an authentication pattern that works for servers, too (so no cookies). Your back-end developer will claim it was a “design choice.” Don’t trust them.
  2. The client needs to set an Authorization header with the token. That’s just the symmetrical issue; the API chose not to rely on cookies.

You’ll meet a lot of documentation in the wild that shows headers like this:

Authorization: Bearer <token>

Setting the Authorization header implies you cannot use an HTTP-Only cookie. Of course, you can set the headers of a request using JavaScript. However, this means that the token must be available to JavaScript in the first place. Let’s repeat it once again: it’s ok not to use a cookie and prefer web storage, but be very careful with XSS attacks!

Moreover, this pattern works only for programmatic requests with fetch and XHR. You can’t secure access to the web page itself because the browser won’t set this header automatically during navigation. You just really can’t.

If you need to secure web pages, the backend of your website (which may differ from your actual API that serves data) should use HTTP-only cookies, or you should set a non-HTTP-only cookie manually. Either way, be careful that by using cookies, you are introducing a new vector of attacks.

Not all websites need to be secured this way, though. It’s actually pretty uncommon for public-facing websites. Remember Blitz.js’ motto “secure data, not pages.” But the cookie way is still a pattern you must be aware of.

If you really need to secure a web page, reach out to your backend developer and explain to them that cookies are good. They won’t contradict this claim.

If it’s really not possible to improve the API, you might want to adopt a pattern named “backend-for-frontend” (BFF). Basically, have a tiny server owned by the front-end team that takes care of calling authenticated APIs server-side, among other things. It works pretty well with frameworks like Remix or Next.js that have built-in server-oriented features.

Side Note On Basic Auth: Looks Like A Header, Behaves Like A Cookie

Of course, every rule must have its exceptions. There is only one common scenario I know where the token can be passed as a request header without using JavaScript: using basic authentication.

Basic authentication is an unsafe pattern, as identifiers are sent alongside every request, not just a token but the actual username and password. It’s a bit like asking your local drug dealer to pay your rent and give them your ID card and 2000$ that they should kindly bring to your landlord. It’s only ok if this is a fake ID. Actually, no, fake IDs and drug dealers are not ok. But you get the point!

It’s still interesting for a few use cases, like quickly securing the demo of a website. As long as you can accept the password to be stolen without that many consequences, typically if the password has been generated by an admin for a temporary occasion (NOT a user-set password that could be reused for multiple services!).

In basic authentication, the browser sets the Authorization header for you. You still need to set the credentials option properly when using fetch programmatically so that the header is also set in this case. But you don’t have to manually tweak the header. It really behaves like a cookie.

That’s actually one reason why this fetch option is named “credentials” and not just “cookies”: it also applies to the basic authentication header.

Conclusion

Wow, if you’ve read this far, you definitely earned your right to a quick summary!

But before that, I have another gift for you: an open-source demo of authentication with Deno and HTMX for the front end!

This is a very basic setup, but it puts the concepts described in this article into action using the “cookie way.”

Here is your well-deserved TL;DR:

  • JWT is like banknotes, and sessionId is like credit cards. They are two authentication patterns, but either way, you want to store those tokens safely client-side.
  • One safe place to store tokens in a browser is an HTTP-only and secure cookie, set via the Set-Cookie header of the login response. It cannot be stolen by malicious JavaScript code. Web storage is another possibility if you only secure API calls and not web page access. If you pick web storage, then be very careful with XSS attacks.
  • Cookies are automatically sent alongside every request provided you use the right options, namely the path and SameSite attributes of the cookie. Like a wallet, you would carry it on you all the time and take it out of your bag only in safe places when a payment is needed.
  • When navigating via URL, the browser takes care of sending the cookie containing the auth token (if properly set). But you may also need to call authenticated APIs using JavaScript code. Fetch credentials and XHR withCredentials options have to be configured correctly, so cookies are also sent alongside those programmatic requests. Don’t forget to set the Access-Control-Allow-Credentials response header as well.
  • Auth is about politeness: the server must set the proper headers for everything to work. You can’t enter a bank and yell at people to get your money.
  • This is particularly true for cross-origin requests. Companies must have secure and polite discussions with their bank, which can be separate organizations or located in a distant country. That’s what CORS is for websites and APIs. Don’t forget to properly set the Access-Control-Allow-Origin and Access-Control-Allow-Credentials headers in the response.
  • If you store your savings in your mailbox, put a camera on top of it, and if you store your token in the web storage, protect it against XSS attacks.
  • Banks don’t treat people like they treat other banks. Don’t confuse webpages patterns (have to rely on cookies and browser’s built-in features) and API patterns (relying on headers, which can be implemented using client-side JavaScript).
  • Basic auth is a fun pattern that blurs the line, as it uses an Authorization header like for APIs, but it can be used for webpages too. It’s a specific and very insecure pattern that is only meant for a handful of limited use cases. Basic auth headers are a reason why fetch and XHR options are named “credentials” and not just “cookies.”

Resources

How to Store Text in PostgreSQL: Tips, Tricks, and Traps

DDL generation based on JPA entities definition is a daily task for many developers. In most cases, we use tools like Hibernate's built-in generator or JPA Buddy plugin. They make the job easier, but there are exceptions. When it comes to storing big chunks of data in the database, things get a bit complicated.

Use Case: Storing Documents 

Let’s assume we need to store a document object with its content in the PostgreSQL database. The JPA entity code for this might look like the code below:

Fixing Registered Callback Issue in an Active-Active Setup of WSO2 APIM

This article shows how we can fix the registered callback issue which occurs when you have an Active-Active setup of WSO2 APIM with a shared database.

Use Case

We have 2 nodes or machines “hostA” and “hostB” where WSO2 APIM 3.2.0 is set up in an Active-Active mode. Both of the nodes share the same “apim” and “shared” databases created in Oracle.

Import Mule Application as Project Libraries For Shared Resources

Use Case: If we want to use shared resources or common global configuration from one of Mule application into another Mule application then this article could guide us to achieve this use case.

In Mule 4, Anypoint Studio’s built-in Maven support for any Mule Projects has provided a great feature where any Mule applications can be packaged into a deployable JAR file. This package contains the application and all its dependencies. It can be used as JAR file or as a mule plugin.We can also used it as a utility application referencing through project libraries. In our use case we are going to use one Mule application as utility application into another Mule application.

Real-Time Stream Processing With Apache Kafka Part 4: Use Case

In previous articles, we have gained the ground on understanding basic terminologies used in Kafka and Kafka-Streams. In this article, we set up a single node kafka cluster on our Windows machine. Now, based on the knowledge we have gained so far, let us try to build a use case.

Scenario

Consider a hypothetical fleet management company that needs a dashboard to get the insight of its day to day activities related to vehicles. Each vehicle in this fleet management company is fitted with a GPS based geolocation emitter, which emits location data containing the following information

7 Gorgeous Free And Open-Source Typefaces And When To Use Them

7 Gorgeous Free And Open-Source Typefaces And When To Use Them

7 Gorgeous Free And Open-Source Typefaces And When To Use Them

Noemi Stauffer

To facilitate your font picking and pairing process, I’ve included examples of how these typefaces have been put to use recently, as well as a few pairing ideas. Enjoy and don’t forget to ping me on Twitter to show me how you’ve used them — I’d love to see it!

Gangster Grotesk

Designed by Adrien Midzic, Gangster Grotesk is a contemporary grotesque with angled terminal strokes that slightly curve inward. Because of these quirky individual touches, the typeface brings a unique flavor to headlines and posters when used at large sizes. Its low contrast and slightly condensed width make it a good choice for body copy and other texts of small type sizes as well.

The font family comes in three weights, from Light to Bold, with stylistic alternates, including a loopy expressive ampersand. Gangster Grotesk is offered for free when signing up for the Fresh Fonts newsletter.

Preview of Gangster Grotesk
Gangster Grotesk. (Large preview)

Suggested Font Pairings

When applying Gangster Grotesk to titles, the quirky grotesque pairs well with low x-height serifs for text settings, such as FF Atma. Used at small point sizes instead, pairing Gangster Grotesk with Le Murmure (see below) offers the right mix of character and neutrality.

Use Case

Gangster Grotesk excels in punchy designs with strong colors when it’s asked to render strings of text, for example on this flyer designed by Tokyo-based Juri Okita for Pells Coffee.

An example of Gangster Grotesk in use
Gangster Grotesk in use. (Large preview)

Le Murmure

Preview of Le Murmure
Le Murmure. (Large preview)

Recently awarded a Certificate of Typographic Excellence by the Type Directors Club, Le Murmure was commissioned by French design agency Murmure to renew their brand image. Drawing inspiration from magazine titling fonts, Le Murmure is a condensed sans serif with an interesting mismatch between its characters, making it especially distinctive for use at large sizes. Its height and the singularity of its shapes provide elegance while conveying notions of experimentation and creativity. Le Murmure comes with many — even more — original alternate letters, and there is even a stylistic set that ‘randomizes’ all alternates for you (SS08).

Suggested Font Pairings

Used as a titling font, Le Murmure can pair well with a sans serif with warm curves, like Standard CT, or with a sans that has more pronounced irregularities, like Dinamo’s Prophet.

Use Case

Marrakesh’s Untitled Duo picked Le Murmure for the headlines of their studio’s website, complemented with Classic Sans for the navigation, which they also used at smaller size for the body text.

An example of Le Murmure in use
Le Murmure in use. View full website. (Large preview)
An example of Le Murmure in use
Le Murmure in use. View full website. (Large preview)

Reforma

Preview of Reforma
Reforma. (Large preview)

Reforma is a bespoke typeface designed by PampaType for the Universidad Nacional de Córdoba in Argentina, an educational institution more than 400 years old. The typeface is composed of three subfamilies: Reforma 1918, a classic Serif, Reforma 2018, a modern Sans, and Reforma 1969, an intermediate hybrid that combines the qualities of the other two (subtle modulation and flare serifs). I find all three subfamilies to adapt well to a wide range of bodies, from display to immersive text, and each one of them comes in three weights, with matching italics.

Suggested Font Pairings

This typeface allows for interesting combinations among its different styles. The most obvious would be to use Reforma Sans for display use and to pair it with its serif counterpart for body text. However, I would encourage you to do something more original and try it the other way around, using the serif for titling.

Use Case

Graphic designer Étienne Pouvreau chose Reforma for the creation of the annual programs of the two Caf family centers of the Loir-et-Cher department in France. The booklets feature Reforma 1918 (the serif) for the headings, in italic, and Reforma 2018 (the sans) for the titles, subtitles and body text.

An example of Reforma in use
Reforma in use. View full booklet. (Large preview)

Space Grotesk

Preview of Space Grotesk
Space Grotesk. (Large preview)

The new foundry of Florian Karsten is behind this versatile, geometric sans serif. Derived from Space Mono, a monospaced typeface designed by Colophon Foundry for Google Fonts in 2016, Space Grotesk kept the nerdy charm of its predecessor and its particular retro-future voice. Available in five weights, Space Grotesk is well-suited for a wide range of uses, from body text to bold headlines. In addition, it comes with five sets of alternate letters, the third one (SS03) removing the connections between the diagonal strokes of uppercase A, M, N, V, W, and lowercase v, w, y  — which can be particularly effective to create distinctive headlines.

Suggested Font Pairings

As one would guess, Space Grotesk pairs well with Colophon Foundry’s Space Mono, the typeface it was derived from, which is also open source and free to use. Alternatively, if you’d like to pair it with a serif typeface, I would recommend one with pointy serifs and sharp details, such as Fortescue, or Wremena, which is also free to use (see below).

Use Case

Little & Big, a web design and development studio based in Sydney, Australia, chose Space Grotesk as the body text font for their website, including on blog entries, header and footer. They decided to pair it with Verona Serial, giving the website a professional, yet playful look and feel.

An example of Space Grotesk in use
Space Grotesk in use. View full website. (Large preview)
An example of Space Grotesk in use
Space Grotesk in use. View full website. (Large preview)

Syne

Preview of Syne
Syne. (Large preview)

Syne is a type family designed by Bonjour Monde for the visual identity of Synesthésie, an art center close to Paris. It consists of five distinct styles, amplifying the notion of structural differentiation within a font family: Syne Extra is a wide, heavy weight intended for use at large sizes, Syne Regular is a geometric sans with short ascenders and descenders (visible in the lowercase ‘g’ among others), complemented with a wider bold style, an italic in a handwritten style and a monospaced with a distorted look. Updated just days ago, Syne now comes with more alternates, a set of brand new accents, and a variable font version.

Suggested Font Pairings

The particularity of this typeface is that you can play with its different styles, and create fresh and atypical associations among them. For instance, Syne Extra does wonder for titles and headlines, and works well with Syne Regular for body copy.

Use Case

Syne was recently used by WeTransfer to present the results of their Ideas Report 2018, making extensive use of the typeface’s five different cuts on the website of the report and on its beautiful PDF companion.

An example of Syne in use
Syne in use. View full website. (Large preview)
An example of Syne in use
Syne in use. View full website. (Large preview)

VG5000

Preview of VG5000
VG5000. (Large preview)

Named after the VG 5000, a computer created by Phillips in 1984, this typeface playfully combines pixelated and curved strokes, blurring the lines between old and new digital shapes. It also includes many early emojis and pictograms from the VG 5000’s original set, allowing you to create unexpected combinations. Moreover, the typeface comes with contemporary gender inclusive characters for the French language, replacing pronouns “il” and “elle” (“he” and “she”) with the neutral “iel”, and providing an alternative to gendered words by combining their masculine and feminine versions.

Suggested Font Pairings

Because of its pixelated details, and to remain truthful to its origins, I would suggest pairing VG5000 with a monospaced font, for example League Mono, which is also open source. Alternatively, you could decide to pair it with the sans or serif version of Input, or with a semi-proportional typeface like ETC Trispace, which is also free.

Use Case

French design studio Brand Brothers put VG5000 to use for the visual identity of Les Halles de la Cartoucherie, a new, versatile space dedicated to cultural, artistic and gastronomic activities in Toulouse. Paired with a custom, grid-based logo that represents the structure of the space, VG5000 was used both at large and small sizes on print materials, on the website of the space and even on its walls, using VG5000's pixelated arrows for its wayfinding system.

An example of VG5000 in use
VG5000 in use. View full project. (Large preview)
An example of VG5000 in use
VG5000 in use. View full project. (Large preview)

Wremena

Preview of Wremena
Wremena. (Large preview)

Wremena is a serif typeface designed by Roman Gornitsky and published by Moscow-based foundry Typefaces of The Temporary State. Its design was based on Vremena, a free typeface by the same designer, but it features more pronounced triangular serifs and sharper angles, which become even more visible in heavier weights. Wremena is available in three styles (Light, Regular and Bold) without italics but with support for the Latin and Cyrillic scripts. Because of its similarities with Times New Roman, Wremena can be used as a free, more contemporary alternative to the ever-popular typeface.

Suggested Font Pairings

A good tip to find pairings for a specific font is to browse the library of typefaces created by the same designer, as they often pair well together. This is especially true in this case, as Roman Gornitsky designed two sans serifs that are great matches for Wremena: Nowie Vremena, with its distinctive lowercase ‘g’, and more recently, Steinbeck, a lively font with intentional irregularities.

Use Case

The Jewish Museum of Moscow is behind Russian Spleen, a picturesque interactive web project that explores how Russian landscape painter Isaac Levitan impacted the 20th-century cinematography. Designer Pavel Kedich decided to typeset the website in Steinbeck (used at large sizes) and Wremena (here used for captions). Both fonts being multi-script, they allow the website to be available in English and Russian languages.

An example of Wremena in use
Wremena in use. View full website. (Large preview)
An example of Wremena in use
Wremena in use. View full website. (Large preview)

That’s It For Now!

While I’ve included great examples of how these free fonts can be used, there are many more on Typewolf and Fonts in Use. And if you’d like to discover new, high-quality free and open source fonts, make sure to subscribe to my newsletter Fresh Fonts.

All works and screenshots are property of their respective owners.

Smashing Editorial (ah, yk, il)

A Few Functional Uses for Intersection Observer to Know When an Element is in View

You might not know this, but JavaScript has stealthily accumulated quite a number of observers in recent times, and Intersection Observer is a part of that arsenal. Observers are objects that spot something in real-time — like birdwatchers going to their favorite place to sit and wait for the birds to come.

Different observers observe different things (not everyone watches hawks).

The very first observer I came to know was the Mutation Observer that looks for changes to the DOM tree. It was a one-of-a-kind at the time, but now we have many more observers.

Intersection Observer observes the "intersection" (i.e. the passing across) of an element through one of its ancestor elements or the area on screen where the page is visible (aka the viewport).

It’s sort of like watching a train pass through a station. You can see when the train comes in, when it leaves, and how long it was stationary.

Knowing when an element is about to come into view, if it has gone out of view, or how long it’s been since it came into view all have useful applications. So, we’ll see some of those use cases now — right after seeing the code for creating an IntersectionObserver object by way of the Intersection Observer API.

A quick overview of IntersectionObserver

The Intersection Observer API has already gained wide support at the time of this writing.

This browser support data is from Caniuse, which has more detail. A number indicates that browser supports the feature at that version and up.

Desktop

ChromeOperaFirefoxIEEdgeSafari
584555No1612.1

Mobile / Tablet

iOS SafariOpera MobileOpera MiniAndroidAndroid ChromeAndroid Firefox
12.246No677466

But if you want to check whether Intersection Observer is supported while you’re working with it, you could see if the property IntersectionObserver exists in the window object:

if(!!window.IntersectionObserver){}
/* or */
if('IntersectionObserver' in window){}

OK, now for a look at the object creation:

var observer = new IntersectionObserver(callback, options);

The IntersectionObserver object’s constructor takes two parameters. The first one is a callback function that’s executed once the observer notices an intersection and has asynchronously delivered some data about that intersection.

The second (optional) parameter is options, an object with information to define what’s going to be the "intersection." We may not want to know when an element is about to come into view, but only when it’s fully visible. Something like that is defined through the options parameter.

Options has three properties:

  • root - The ancestor element/viewport that the observed element will intersect. Think of it as the train station that the train will intersect.
  • rootMargin - A perimeter of the root element, shrinking or growing the root element’s area to watch out for intersection. It’s similar to the CSS margin property.
  • threshold - An array of values (between 0 and 1.0), each representing the distance an element has intersected into or crossed over in the root at which the callback is to be triggered.

Let’s say our threshold is 0.5. The callback is triggered when the element is in or passes its half-visible threshold. If the value is [0.3, 0.6], then the callback is triggered when the element is in or passes its 30% visible threshold and also, its 60% visible threshold.

That’s enough of the theory now. Let’s see some demos. First up, lazy loading.

Use Case 1: Lazy loading images

See the Pen
Intersection Observer - Lazy Load
by Preethi Sam (@rpsthecoder)
on CodePen.

To see the loading at the mark, view this webpage since the embedded demo doesn't show that.

CSS-Tricks has thoroughly covered lazy loading in before and it’s typically done like this: display a lightweight placeholder where images are intended, then swap them out for the intended images as they come (or are about to come) into view. Believe me, there’s nothing lazy about implementing this — that is, until we get something native to work with.

We’ll apply the same mechanics. First, we’ve a bunch of images and have defined a placeholder image to display initially. We’re using a data attribute carrying the URL of the original image to be shown that defines the actual image to load when it comes into view.

<img src="placeholder.png" data-src="img-1.jpg">
<img src="placeholder.png" data-src="img-2.jpg">
<img src="placeholder.png" data-src="img-3.jpg">
<!-- more images -->

The rest is scripting.

let observer = new IntersectionObserver(
(entries, observer) => { 
  entries.forEach(entry => {
    /* Here's where we deal with every intersection */
  });
}, 
{rootMargin: "0px 0px -200px 0px"});

The callback function above is an arrow function (though you can use a normal function instead).

The callback function receives two parameters: a set of entries carrying the information about each intersection and the observer itself. Those entries can be filtered or looped through so we can then deal with the intersection entries that we want. As for the options, I’ve only provided the rootMargin value, letting the root and threshold properties fall into their default values.

The root default is the viewport and threshold default is 0 — which can be roughly translated to "ping me the very moment that the element appears in the viewport!"

The oddity, though, is that I reduced the viewport’s observation area by two hundred pixels at the bottom using rootMargin. We wouldn’t typically do this for lazy loading. Instead, we might increase the margin or let it default. But reducing isn’t something we would usually do in this situation. I did it only because I want to demonstrate the original images loading at the threshold in the observed area. Otherwise, all the action would happen out of view.

When the image intersects the viewport’s observer area (which is 200px above the bottom in the demo), we replace the placeholder image with the actual image.

let observer = new IntersectionObserver(
(entries, observer) => { 
entries.forEach(entry => {
    /* Placeholder replacement */
    entry.target.src = entry.target.dataset.src;
    observer.unobserve(entry.target);
  });
}, 
{rootMargin: "0px 0px -200px 0px"});

entry.target is the element observed by the observer. In our case, those are the image elements. Once the placeholder is replaced in an image element, we don’t have to observe it anymore, so we call the observer’s unobserve method for it.

Now that the observer is ready, it’s time to start observing all the images by using its observer method:

document.querySelectorAll('img').forEach(img => { observer.observe(img) });

That’s it! we’ve lazy loaded the images. Onto the next demo.

Use Case 2: Auto-pause video when it’s out of view

Let’s say we’re watching a video on YouTube and (for whatever reason) we want to scroll down to read the comments. I don’t know about you, but I don’t usually pause the video first before doing that, which means I miss some of the video while I’m browsing.

Wouldn’t it be nice if the video paused for us when we scroll away from it? It would be even nicer if the video resumed when it’s back in view so there’s no need to hit Play or Pause at all.

Intersection Observer can certainly do that.

See the Pen
IntersectionObserver: auto-pause out of view video
by Preethi Sam (@rpsthecoder)
on CodePen.

Here’s our video in the HTML:

<video src="OSRO-animation.mp4" controls=""></video>

Here’s how we toggle between play and pause:

let video = document.querySelector('video');
let isPaused = false; /* Flag for auto-paused video */
let observer = new IntersectionObserver((entries, observer) => { 
  entries.forEach(entry => {
    if(entry.intersectionRatio!=1  && !video.paused){
      video.pause(); isPaused = true;
    }
    else if(isPaused) {video.play(); isPaused=false}
  });
}, {threshold: 1});
observer.observe(video);

Before I show you how we’re pausing and playing the video during each intersection (i.e. entry), I want to bring your attention to the threshold property of the options.

Th threshold has a value of 1. Both root and rootMargin will default. This is the same as saying, "hey, let me know as soon the element is fully visible on the viewport."

Once the intersection happens and the callback is triggered, we pause or play the video based on this logic:

A flow chart for toggling play and pause on a video, where if video not fully visible and not paused, then isPaused is true. But if video was auto-paused, then IsPaused is false.

I have not called unobserve for the video, so the observer keeps observing the video and pauses every time it goes out of view.

Use Case 3: See how much content is viewed

This can be interpreted and implemented in many ways depending on what your content is and the way you prefer to measure how much of it has been viewed.

For a simple example, we’ll observe the last paragraph of every article in a list of articles on a page. Once an article’s last paragraph becomes fully visible, we will consider that article read — like how we might say that seeing the last coach of a train counts as having seen the whole train.

Here’s a demo that shows two articles on a page, each containing a number of paragraphs.

See the Pen
IntersectionObsever: content viewed
by Preethi Sam (@rpsthecoder)
on CodePen.

Our simplified HTML is something like this:

<div id="count"><!-- The place where "number of articles viewed" is displayed --></div>

<h2>Article 1</h2>
<article>
  <p><!-- Content --></p>
  <!-- More paragraphs -->
</article>
<h2>Article 2</h2>
<article>
  <p><!-- Content --></p>
  <!-- More paragraphs -->
</article>
<!-- And so on... -->
let n=0; /* Total number of articles viewed */
let count = document.querySelector('#count');
let observer = new IntersectionObserver((entries, observer) => { 
  entries.forEach(entry => {
    if(entry.isIntersecting){
      count.textContent= `articles fully viewed - ${++n}`; 
      observer.unobserve(entry.target);
    }
  });
}, {threshold: 1});

document.querySelectorAll('article > p:last-child').forEach(p => { observer.observe(p) });

During each intersection — the full view of the last paragraph of an article — we’re incrementing a count: n, that represents the total number of articles read. Then we display that number above the list of articles.

Once we’ve counted in an intersection of the last paragraph, it doesn’t need to be observed anymore, so we call unobserve for it.

Thanks for observing along!

That’s it for the examples we’re going to look at together for this post. You probably get the idea of how using it is, to be able to observe elements and trigger events based on where they intersect the viewport.

That said, it’s worth using caution when making visual changes based on the intersection data obtained through the observer. Sure, Intersection Observer is hassle free when it comes to logging intersection data. But when it’s being used to make onscreen changes, we need to ensure the changes aren’t lagging, which is a possibility because we’re basically making changes based on data retrieved asynchronously. That might require a little bit of time to load.

As we saw, each intersection entry has a set of properties conveying information about the intersection. I didn’t cover all of them in this post, so be sure to review them.

The post A Few Functional Uses for Intersection Observer to Know When an Element is in View appeared first on CSS-Tricks.