Good morning to everyone at #smsociety. This tweet should be included in a demo network that’s being created as part of today’s NodeXL workshop
{
"type": "entry",
"published": "2019-07-19T13:48:44+00:00",
"url": "https://twitter.com/jackjamieson/status/1152213684334317568",
"content": {
"text": "Good morning to everyone at #smsociety. This tweet should be included in a demo network that\u2019s being created as part of today\u2019s NodeXL workshop",
"html": "Good morning to everyone at <a href=\"https://twitter.com/search?q=%23smsociety\">#smsociety</a>. This tweet should be included in a demo network that\u2019s being created as part of today\u2019s NodeXL workshop"
},
"author": {
"type": "card",
"name": "Jack Jamieson",
"url": "https://twitter.com/jackjamieson",
"photo": "https://aperture-proxy.p3k.io/8643be4b957e7661060801db20570b1d43fb2f87/68747470733a2f2f7062732e7477696d672e636f6d2f70726f66696c655f696d616765732f3830303833353732373339313132353530352f746f316c536256702e6a7067"
},
"post-type": "note",
"_id": "4536908",
"_source": "2773"
}
Real breakfast place was closed so having bagel backup breakfast instead
{
"type": "entry",
"published": "2019-07-19T08:37:42-05:00",
"url": "https://aaronparecki.com/2019/07/19/5/",
"syndication": [
"https://www.swarmapp.com/user/59164/checkin/5d31c7a6e9235a00087b3e1f"
],
"content": {
"text": "Real breakfast place was closed so having bagel backup breakfast instead"
},
"author": {
"type": "card",
"name": "Aaron Parecki",
"url": "https://aaronparecki.com/",
"photo": "https://aperture-media.p3k.io/aaronparecki.com/41061f9de825966faa22e9c42830e1d4a614a321213b4575b9488aa93f89817a.jpg"
},
"checkin": {
"type": "card",
"name": "Meshuggah Bagels",
"latitude": "39.098606",
"longitude": "-94.58253",
"url": "https://foursquare.com/v/5b69b0e65d891b002c20e4c8"
},
"post-type": "checkin",
"_id": "4536787",
"_source": "16"
}
{
"type": "entry",
"published": "2019-07-19T09:39:50+0000",
"url": "https://quickthoughts.jgregorymcverry.com/2019/07/19/writing-prompt-day-four-edu407sum19",
"syndication": [
"https://twitter.com/jgmac1106/status/1152151063526629377"
],
"name": "Writing Prompt Day Four #EDU407Sum19",
"content": {
"text": "Writers thrive on the power of observation.Look up. The sky is its own canvas of wonder.\u00a0 Imagine this: we all share the same sky, just different parts of it at different times of day. Your sky is part of my sky, and mine, is part of yours.For today\u2019s prompt, gaze up at the sky, day or night or somewhere in-between, and take notice. We suggest you find a nice plot of ground to lay back on and then just become quiet. Looking, wondering, wandering at the expanse above you. How does the sky inform your world?Adapted From: https://dailyconnector.com/2019/07/18/clmooc-feldgang-variations-the-open-sky/\">https://dailyconnector.com/2019/07/18/clmooc-feldgang-variations-the-open-sky/",
"html": "<p>Writers thrive on the power of observation.</p><p>Look up. The sky is its own canvas of wonder.\u00a0 Imagine this: we all share the same sky, just different parts of it at different times of day. Your sky is part of my sky, and mine, is part of yours.</p><p>For today\u2019s prompt, gaze up at the sky, day or night or somewhere in-between, and take notice. We suggest you find a nice plot of ground to lay back on and then just become quiet. Looking, wondering, wandering at the expanse above you. How does the sky inform your world?</p><p>Adapted From: <a href=\"https://quickthoughts.jgregorymcverry.com/Writers%20thrive%20on%20the%20power%20of%20observation.%20%20Look%20up.%20The%20sky%20is%20its%20own%20canvas%20of%20wonder.%20%20Imagine%20this:%20we%20all%20share%20the%20same%20sky,%20just%20different%20parts%20of%20it%20at%20different%20times%20of%20day.%20Your%20sky%20is%20part%20of%20my%20sky,%20and%20mine,%20is%20part%20of%20yours.%20%20For%20today%E2%80%99s%20prompt,%20gaze%20up%20at%20the%20sky,%20day%20or%20night%20or%20somewhere%20in-between,%20and%20take%20notice.%20We%20suggest%20you%20find%20a%20nice%20plot%20of%20ground%20to%20lay%20back%20on%20and%20then%20just%20become%20quiet.%20Looking,%20wondering,%20wandering%20at%20the%20expanse%20above%20you.%20How%20does%20the%20sky%20inform%20your%20world?%20%20Adapted%20From:%20\">https://dailyconnector.com/2019/07/18/clmooc-feldgang-variations-the-open-sky/</a>\"><a href=\"https://dailyconnector.com/2019/07/18/clmooc-feldgang-variations-the-open-sky/\">https://dailyconnector.com/2019/07/18/clmooc-feldgang-variations-the-open-sky/</a></p>"
},
"author": {
"type": "card",
"name": "Greg McVerry",
"url": "https://quickthoughts.jgregorymcverry.com/profile/jgmac1106",
"photo": "https://aperture-proxy.p3k.io/caeb995d615fbe49086b65db17f0eae5d43ef188/68747470733a2f2f717569636b74686f75676874732e6a677265676f72796d6376657272792e636f6d2f66696c652f32643663396366656437616338653834396634393262356263376536613633302f7468756d622e6a7067"
},
"post-type": "article",
"_id": "4534681",
"_source": "1300"
}
{
"type": "entry",
"published": "2019-07-19T09:39:54+00:00",
"url": "https://twitter.com/jgmac1106/status/1152151063526629377",
"content": {
"text": "Writing Prompt Day Four #EDU407Sum19: quickthoughts.jgregorymcverry.com/2019/07/19/wri\u2026",
"html": "Writing Prompt Day Four <a href=\"https://twitter.com/search?q=%23EDU407Sum19\">#EDU407Sum19</a>: <a href=\"https://quickthoughts.jgregorymcverry.com/2019/07/19/writing-prompt-day-four-edu407sum19\">quickthoughts.jgregorymcverry.com/2019/07/19/wri\u2026</a>"
},
"author": {
"type": "card",
"name": "https://jgregorymcverry.com",
"url": "https://twitter.com/jgmac1106",
"photo": "https://aperture-proxy.p3k.io/5163db442c9bc69839ca550f18eb71e1b0ca8162/68747470733a2f2f7062732e7477696d672e636f6d2f70726f66696c655f696d616765732f3536353232373731303130343838333230302f67344d4463546e782e6a706567"
},
"post-type": "note",
"_id": "4534513",
"_source": "2773"
}
I’m enjoying the final splatfest. Also I keep seeing @orcastraw on the news box for winning battles. You go!
{
"type": "entry",
"published": "2019-07-19T05:57:46+00:00",
"url": "https://twitter.com/fluffy/status/1152095165105885188",
"category": [
"https://twitter.com/orcastraw"
],
"content": {
"text": "I\u2019m enjoying the final splatfest. Also I keep seeing @orcastraw on the news box for winning battles. You go!",
"html": "I\u2019m enjoying the final splatfest. Also I keep seeing <a href=\"https://twitter.com/orcastraw\">@orcastraw</a> on the news box for winning battles. You go!"
},
"author": {
"type": "card",
"name": "fluffy",
"url": "https://twitter.com/fluffy",
"photo": "https://aperture-proxy.p3k.io/6776e53f9c2bb77f83c692f04b54d5d295ab745c/68747470733a2f2f7062732e7477696d672e636f6d2f70726f66696c655f696d616765732f313131333235383031363135313730373634382f767a7065584346742e706e67"
},
"post-type": "note",
"refs": {
"https://twitter.com/orcastraw": {
"type": "card",
"name": "Kaitlyn",
"url": "https://twitter.com/orcastraw",
"photo": null
}
},
"_id": "4532859",
"_source": "2773"
}
I could do without the mosquitoes but otherwise this place is 💯 (completely blows my mind this vast green is 5mins from Shinjuku Station🤯) (@ Shinjuku Gyoen in 新宿区, 東京都) swarmapp.com/c/axA7XoIaz3m
{
"type": "entry",
"published": "2019-07-19T05:17:24+00:00",
"url": "https://twitter.com/slsoftworks/status/1152085006203924480",
"photo": [
"https://aperture-proxy.p3k.io/6afbc2c23f45548096adf22af25e99f713a538c8/68747470733a2f2f7062732e7477696d672e636f6d2f6d656469612f445f30484e543557344141704b524d2e6a7067"
],
"content": {
"text": "I could do without the mosquitoes but otherwise this place is \ud83d\udcaf (completely blows my mind this vast green is 5mins from Shinjuku Station\ud83e\udd2f) (@ Shinjuku Gyoen in \u65b0\u5bbf\u533a, \u6771\u4eac\u90fd) swarmapp.com/c/axA7XoIaz3m",
"html": "I could do without the mosquitoes but otherwise this place is \ud83d\udcaf (completely blows my mind this vast green is 5mins from Shinjuku Station\ud83e\udd2f) (@ Shinjuku Gyoen in \u65b0\u5bbf\u533a, \u6771\u4eac\u90fd) <a href=\"https://www.swarmapp.com/c/axA7XoIaz3m\">swarmapp.com/c/axA7XoIaz3m</a>"
},
"author": {
"type": "card",
"name": "flaki",
"url": "https://twitter.com/slsoftworks",
"photo": "https://aperture-proxy.p3k.io/6285144b4ec9009aa695015b76d5cdc404cd8fb6/68747470733a2f2f7062732e7477696d672e636f6d2f70726f66696c655f696d616765732f3734393637383638333531343839363338352f37677849526e6f432e6a7067"
},
"post-type": "photo",
"refs": {
"https://aperture-proxy.p3k.io/6afbc2c23f45548096adf22af25e99f713a538c8/68747470733a2f2f7062732e7477696d672e636f6d2f6d656469612f445f30484e543557344141704b524d2e6a7067": {
"type": "image",
"ratio": 1.33,
"bytes": 218642
}
},
"_id": "4532619",
"_source": "2773"
}
Do any of my followers service their own laptops? This is one of the reasons I’ve stuck with Dell - a consistent 8 screws and I can do upgrades.
I’m curious because I’m in need of potentially adding some replacement parts and wanted suggestions on… v2.jacky.wtf/post/6ef88ef5-…
{
"type": "entry",
"published": "2019-07-19T05:12:43+00:00",
"url": "https://twitter.com/jackyalcine/status/1152083827596173312",
"content": {
"text": "Do any of my followers service their own laptops? This is one of the reasons I\u2019ve stuck with Dell - a consistent 8 screws and I can do upgrades.\n\nI\u2019m curious because I\u2019m in need of potentially adding some replacement parts and wanted suggestions on\u2026 v2.jacky.wtf/post/6ef88ef5-\u2026",
"html": "Do any of my followers service their own laptops? This is one of the reasons I\u2019ve stuck with Dell - a consistent 8 screws and I can do upgrades.\n\nI\u2019m curious because I\u2019m in need of potentially adding some replacement parts and wanted suggestions on\u2026 <a href=\"https://v2.jacky.wtf/post/6ef88ef5-7882-4a15-aae7-f96443336608\">v2.jacky.wtf/post/6ef88ef5-\u2026</a>"
},
"author": {
"type": "card",
"name": "Jacky Alcin\u00e9",
"url": "https://twitter.com/jackyalcine",
"photo": "https://aperture-proxy.p3k.io/af89865555b71ab66d185400dd43a315963ddf76/68747470733a2f2f7062732e7477696d672e636f6d2f70726f66696c655f696d616765732f313135313532303433303839383837323332302f4a656259646c336e2e6a7067"
},
"post-type": "note",
"_id": "4532620",
"_source": "2773"
}
Do any of my followers service their own laptops? This is one of the reasons I’ve stuck with Dell - a consistent 8 screws and I can do upgrades.
I’m curious because I’m in need of potentially adding some replacement parts and wanted suggestions on places that aren’t eBay.
{
"type": "entry",
"published": "2019-07-18T22:12:00.00000-07:00",
"url": "https://v2.jacky.wtf/post/6ef88ef5-7882-4a15-aae7-f96443336608",
"content": {
"text": "Do any of my followers service their own laptops? This is one of the reasons I\u2019ve stuck with Dell - a consistent 8 screws and I can do upgrades.\nI\u2019m curious because I\u2019m in need of potentially adding some replacement parts and wanted suggestions on places that aren\u2019t eBay.",
"html": "<p>Do any of my followers service their own laptops? This is one of the reasons I\u2019ve stuck with Dell - a consistent 8 screws and I can do upgrades.</p>\n<p>I\u2019m curious because I\u2019m in need of potentially adding some replacement parts and wanted suggestions on places that aren\u2019t eBay.</p>"
},
"author": {
"type": "card",
"name": "Jacky Alcin\u00e9",
"url": "https://v2.jacky.wtf",
"photo": "https://aperture-proxy.p3k.io/9f6c6c125a7640abc3c67f876753b4bf233d06d6/68747470733a2f2f76322e6a61636b792e7774662f6d656469612f70726f66696c652d696d616765"
},
"post-type": "note",
"_id": "4532555",
"_source": "1886"
}
{
"type": "entry",
"published": "2019-07-18T23:18:43-05:00",
"url": "https://aaronparecki.com/2019/07/18/17/adding-identity-to-xyz",
"category": [
"oauth",
"xyz",
"txaz"
],
"name": "Adding Identity to OAuth XYZ",
"content": {
"text": "The new draft spec at OAuth.xyz outlines a potential way to completely re-think OAuth from the ground up.\n\nThe XYZ spec, also nicknamed Transactional Authorization, effectively consolidates all of the different variations of OAuth that have evolved over the last decade, and plugs up a few security holes as well.\n\nOAuth 2.0 has served us well over the last 10+ years, and has even been extensible enough to evolve to meet the new requirements of things like mobile apps and apps running on devices that don't have a browser or keyboard. It's hard to imagine that OAuth was originally created before the iPhone existed! That said, this extensibility has sometimes come at the cost of additional complexity, or at the cost of security. Many of the original assumptions that were made while designing OAuth 2.0 no longer apply, and the world of online security is very different today than it was 10 years ago.\n\nThe XYZ spec takes everything the industry has learned from OAuth 2.0 and OpenID Connect over the years and consolidates them into a uniform pattern, reducing reliance on less-secure communications channels, and building in flexibility in a consistent way.\n\nIf you're interested in the details of XYZ, the website oauth.xyz does a great job of laying out all the use cases with examples.\n\nThis post is not an overview of what XYZ is. Instead, what I'd like to talk about today is a suggestion for extending XYZ even further to encompass some additional use cases that have emerged, specifically about adding the user's identity information to the core protocol.\n\nIdentity has always been part of OAuth\n\nOAuth was never intended to communicate information about the user who logged in to the app. This is a common point of confusion, usually wrapped up in the \"authorization vs authentication\" discussion. OAuth was originally created to give third party apps access to a user's account to read or write data at the API.\n\nNaturally, many apps that want access to a user's resources also want to know who that user is. What ended up happening is most OAuth APIs added an endpoint that returns profile information about the user when requested with the access token. You can see this in common APIs like GitHub, Instagram, and Twitter. These were all developed independently, so they all work slightly differently and return data in slightly different formats.\n\nGitHub\n\nhttps://api.github.com/user\nAuthorization: Bearer XXXX\n\n\n{\n \"login\": \"aaronpk\",\n \"id\": 1234,\n \"node_id\": \"MDQ6VXNlcjE=\",\n \"avatar_url\": \"https://avatars3.githubusercontent.com/u/113001?s=460&v=4\",\n \"gravatar_id\": \"\",\n \"url\": \"https://api.github.com/users/aaronpk\",\n ...\n}\n\n\nInstagram\n\nhttps://api.instagram.com/v1/users/self/?access_token=XXXX\n\n\n{\n \"data\": {\n \"id\": \"1574083\",\n \"username\": \"aaronpk\",\n \"full_name\": \"Aaron Parecki\",\n \"profile_picture\": \"https://scontent-dfw5-2.cdninstagram.com/vp/a37666da4d6b670a849e7b77235e4d56/5DCD3710/t51.2885-19/s320x320/52837124_579812379154942_8897415153306304512_n.jpg?_nc_ht=scontent-dfw5-2.cdninstagram.com\",\n \"bio\": \"OAuth hacker\",\n \"website\": \"https://aaronparecki.com\",\n \"is_business\": false,\n \"counts\": {\n \"media\": 1572,\n \"follows\": 285,\n \"followed_by\": 505\n }\n }\n}\n\n\nTwitter\n\nhttps://api.twitter.com/1.1/account/verify_credentials.json\n\n\n[\n {\n \"id\": 14447132,\n \"id_str\": \"14447132\",\n \"name\": \"Aaron Parecki\",\n \"screen_name\": \"aaronpk\",\n \"location\": \"30,000 feet\",\n ...\n }\n]\n\n\nOpenID Connect\n\nOpenID Connect is built on top of OAuth 2.0 and provides a mechanism for applications to get the identity of the user that signs in. It does this in two ways.\n\nThe idea of returning profile information given an access token was standardized in OpenID Connect in the \"UserInfo Endpoint\". When a provider supports this endpoint, a client can send an access token and get back a representation of the authenticated end user.\n\nOpenID Connect UserInfo Endpoint\n\nhttps://authorization-server.com/userinfo\nAuthorization: Bearer XXXXX\n\n\n{\n \"sub\": \"https://aaronparecki.com/\",\n \"name\": \"Aaron Parecki\",\n \"email\": \"aaron@parecki.com\",\n \"preferred_username\": \"aaronpk\",\n ...\n}\n\n\nThis ends up looking very similar to the provider-specific endpoints that we looked at above.\n\nOpenID Connect ID Tokens\n\nThe other way OpenID Connect deals with identity is by defining a new type of token, an \"ID token\". The ID token is defined as a JSON Web Token (JWT) that encodes the user's profile information. This ID token is then returned in response to an OpenID Connect request, either returned in the redirect URL using the implicit flow, or returned alongside the access token using the authorization code flow.\n\nIn the case of the implicit flow, the application that receives the ID token needs to validate the JWT signature and all the JWT claims, because otherwise anyone could drop an ID token into an application to be signed in. This is a standard part of the plain OpenID Connect workflow.\n\nApplications that also need an access token in addition to the ID token should be using the authorization code flow to obtain the access token, otherwise they are at risk of the access token leaking.\n\nSo if an application is getting both an access token and ID token, the simplest way is to get both via the authorization code flow, so that both tokens end up being returned in the response to exchanging the authorization code at the token endpoint. This ends up looking like the below.\n\nPOST /token\nContent-type: application/x-www-form-urlencoded\n\ngrant_type=authorization_code\n&code=XXXXXXXXX\n&redirect_uri=https://example-app.com/redirect\n&client_id={CLIENT_ID}\n&client_secret={CLIENT_SECRET}\n\n\n{\n \"access_token\": \"SlBV32hkMG\",\n \"token_type\": \"Bearer\",\n \"expires_in\": 3600,\n \"refresh_token\": \"2xMBxBtEp3\",\n \"id_token\": \"eyJhbGciOiJSUzI1...\"\n}\n\n\nThe interesting part about this is that in this case, the ID token validation step can be skipped completely, since validating it would provide no additional benefit. The application already knows it's talking to the right server, it knows the response is coming from that server, and the connection can't be tampered with since it will be made over HTTPS. This means the application can just extract the data it needs from the ID token and use it directly.\n\nThe problem with this approach is that this is essentially providing the application with a point-in-time snapshot of the user's profile information. If their profile information changes, there is no way for the application to get that update unless it either fetches the information from the userinfo endpoint or if the user signs in again. While this may only be a minor annoyance for things like the user's name, it is potentially dangerous for other profile information such as what groups a user belongs to, or other things the application may be relying on to modify its behavior based on the logged-in user.\n\nIt also means that the entire profile information for the user is pushed to the application whether it needs it or not. And again, while this may not be a big deal if the only profile information sent is the user's name and email address, it can be potentially a lot of data such as groups, roles, or other provider-specific information that the authorization server may have about the user.\n\nIdentity in XYZ\n\nWhile we're re-thinking OAuth from the ground up, we should also re-think how identity is handled within the system, while drawing from the experience of widely deployed systems. Rather than returning an ID token with potentially stale or large amounts of user information in the authorization response, let's return only the minimum necessary for the application to function, and let it request additional information that it needs when it needs it.\n\nTransaction Request (Authorization Code Exchange)\n\nIn XYZ, the application takes the interact handle it got from the redirect and makes a POST request back to the authorization server to get an access token. (Described in Transaction Request.)\n\nPOST /authorize\nContent-type: application/json\n\n{\n \"handle\": \"80UPWY2NM33OMUKMKSKU\",\n \"interact_handle\": \"CuD2MrpSXVKvvI6dN2awtNLx-HhZy46hJFDBicG4KoZaCmBofvqPxtm7CDMTsUFuvcmLwi_zUN70cCvalI6ENw\"\n}\n\n\nWe'll extend the response as described next.\n\nTransaction Response (Access Token and User Identity)\n\nIn addition to the access token being returned, the user identifier can also be returned in the same response.\n\nThe transaction response can include just the unique user identifier along with the access token.\n\n{\n \"access_token\": {\n \"value\": \"UM1P9PMHKUR64TB8N6BW7OZB8CDFONP219RP1LT0\",\n \"type\": \"bearer\"\n },\n \"user\": {\n \"id\": \"5035678642\"\n }\n}\n\n\nThis property is analogous to the \"sub\" property in an ID token. This value MUST uniquely identify this user within the system, and MUST be consistent when the same user logs in to the same application. The value MAY vary for the same user when logging in to different applications in order to preserve the user's privacy, preventing different applications from cross-correlating users between apps. (This is based on the deployed behavior of several APIs such as Facebook's \"app-scoped IDs\" and Apple's app-specific user ID and proxy email address.)\n\nIf the application needs to know profile information about the user, it can get that from the userinfo endpoint using the access token it just obtained.\n\nWe can go one step further and also return the userinfo endpoint at the same time as returning the user's unique identifier, avoiding the need for the app developer to hard-code this value in the app or find it in a separate discovery spec.\n\n{\n \"access_token\": {\n \"value\": \"UM1P9PMHKUR64TB8N6BW7OZB8CDFONP219RP1LT0\",\n \"type\": \"bearer\"\n },\n \"user\": {\n \"id\": \"5035678642\",\n \"userinfo\": \"https://authorization-server.com/user/5035678642\"\n }\n}\n\n\nThis provides the additional advantage of the opportunity for the authorization server to use a unique URL per user if it wants (although that is by no means a requirement, since the access token will need to be included in the request too).\n\nIf the application then wants to discover profile information about the user, it can make a request to the userinfo endpoint with the access token:\n\nGET /user/5035678642\nAuthorization: Bearer UM1P9PMHKUR64TB8N6BW7OZB8CDFONP219RP1LT0\n\n\n{\n \"id\": \"5035678642\",\n \"name\": \"Aaron Parecki\",\n \"nickname\": \"aaronpk\",\n \"email\": \"aaron@parecki.com\",\n \"photo\": \"https://aaronparecki.com/images/profile.jpg\",\n \"zoneinfo\": \"America/Los_Angeles\"\n}\n\n\nThis ensures that the application knows that it can get the latest version of the user's profile information whenever it needs to by continuing to make requests to the userinfo endpoint, and prevents the temptation to treat the initial snapshot of the profile information as authoritative.\n\nIf we don't address this need in XYZ, we'll risk ending up in the same situation we're in with OAuth 2.0 where providers end up implementing their own snowflake APIs to let apps find the user's profile information anyway.",
"html": "<p>The new draft spec at <a href=\"http://oauth.xyz\">OAuth.xyz</a> outlines a potential way to completely re-think OAuth from the ground up.</p>\n\n<p>The XYZ spec, also nicknamed Transactional Authorization, effectively consolidates all of the different variations of OAuth that have evolved over the last decade, and plugs up a few security holes as well.</p>\n\n<p>OAuth 2.0 has served us well over the last 10+ years, and has even been extensible enough to evolve to meet the new requirements of things like mobile apps and apps running on devices that don't have a browser or keyboard. It's hard to imagine that OAuth was originally created before the iPhone existed! That said, this extensibility has sometimes come at the cost of additional complexity, or at the cost of security. Many of the original assumptions that were made while designing OAuth 2.0 no longer apply, and the world of online security is very different today than it was 10 years ago.</p>\n\n<p>The <a href=\"https://aaronparecki.com/%5Boauth.xyz/%5D(https://oauth.xyz/)(https://oauth.xyz/)\">XYZ spec</a> takes everything the industry has learned from OAuth 2.0 and OpenID Connect over the years and consolidates them into a uniform pattern, reducing reliance on less-secure communications channels, and building in flexibility in a consistent way.</p>\n\n<p>If you're interested in the details of XYZ, the website <a href=\"http://oauth.xyz\">oauth.xyz</a> does a great job of laying out all the use cases with examples.</p>\n\n<p>This post is not an overview of what XYZ is. Instead, what I'd like to talk about today is a suggestion for extending XYZ even further to encompass some additional use cases that have emerged, specifically about adding the user's identity information to the core protocol.</p>\n\n<h2>Identity has always been part of OAuth</h2>\n\n<p>OAuth was never intended to communicate information about the user who logged in to the app. This is a common point of confusion, usually wrapped up in the \"<a href=\"https://aaronparecki.com/%5Boauth.net/articles/authentication/%5D(https://oauth.net/articles/authentication/)(https://oauth.net/articles/authentication/)\">authorization vs authentication</a>\" discussion. OAuth was originally created to give third party apps access to a user's account to read or write data at the API.</p>\n\n<p>Naturally, many apps that want access to a user's resources also want to know who that user is. What ended up happening is most OAuth APIs added an endpoint that returns profile information about the user when requested with the access token. You can see this in common APIs like <a href=\"https://aaronparecki.com/%5Bdeveloper.github.com/v3/users/#get-the-authenticated-user%5D(https://developer.github.com/v3/users/%23get-the-authenticated-user)(https://developer.github.com/v3/users/%23get-the-authenticated-user)\">GitHub</a>, <a href=\"https://aaronparecki.com/%5Bwww.instagram.com/developer/endpoints/users/#get_users_self%5D(https://www.instagram.com/developer/endpoints/users/%23get_users_self)(https://www.instagram.com/developer/endpoints/users/%23get_users_self)\">Instagram</a>, and <a href=\"https://aaronparecki.com/%5Bdeveloper.twitter.com/en/docs/accounts-and-users/manage-account-settings/api-reference/get-account-verify_credentials%5D(https://developer.twitter.com/en/docs/accounts-and-users/manage-account-settings/api-reference/get-account-verify_credentials)(https://developer.twitter.com/en/docs/accounts-and-users/manage-account-settings/api-reference/get-account-verify_credentials)\">Twitter</a>. These were all developed independently, so they all work slightly differently and return data in slightly different formats.</p>\n\n<h3>GitHub</h3>\n\n<pre><code>https://api.github.com/user\nAuthorization: Bearer XXXX\n</code></pre>\n\n<pre><code>{\n \"login\": \"aaronpk\",\n \"id\": 1234,\n \"node_id\": \"MDQ6VXNlcjE=\",\n \"avatar_url\": \"https://avatars3.githubusercontent.com/u/113001?s=460&v=4\",\n \"gravatar_id\": \"\",\n \"url\": \"https://api.github.com/users/aaronpk\",\n ...\n}\n</code></pre>\n\n<h3>Instagram</h3>\n\n<pre><code>https://api.instagram.com/v1/users/self/?access_token=XXXX\n</code></pre>\n\n<pre><code>{\n \"data\": {\n \"id\": \"1574083\",\n \"username\": \"aaronpk\",\n \"full_name\": \"Aaron Parecki\",\n \"profile_picture\": \"https://scontent-dfw5-2.cdninstagram.com/vp/a37666da4d6b670a849e7b77235e4d56/5DCD3710/t51.2885-19/s320x320/52837124_579812379154942_8897415153306304512_n.jpg?_nc_ht=scontent-dfw5-2.cdninstagram.com\",\n \"bio\": \"OAuth hacker\",\n \"website\": \"https://aaronparecki.com\",\n \"is_business\": false,\n \"counts\": {\n \"media\": 1572,\n \"follows\": 285,\n \"followed_by\": 505\n }\n }\n}\n</code></pre>\n\n<h3>Twitter</h3>\n\n<pre><code>https://api.twitter.com/1.1/account/verify_credentials.json\n</code></pre>\n\n<pre><code>[\n {\n \"id\": 14447132,\n \"id_str\": \"14447132\",\n \"name\": \"Aaron Parecki\",\n \"screen_name\": \"aaronpk\",\n \"location\": \"30,000 feet\",\n ...\n }\n]\n</code></pre>\n\n<h2>OpenID Connect</h2>\n\n<p>OpenID Connect is built on top of OAuth 2.0 and provides a mechanism for applications to get the identity of the user that signs in. It does this in two ways.</p>\n\n<p>The idea of returning profile information given an access token was standardized in OpenID Connect in the \"<a href=\"https://aaronparecki.com/%5Bopenid.net/specs/openid-connect-core-1_0.html#UserInfo%5D(https://openid.net/specs/openid-connect-core-1_0.html%23UserInfo)(https://openid.net/specs/openid-connect-core-1_0.html%23UserInfo)\">UserInfo Endpoint</a>\". When a provider supports this endpoint, a client can send an access token and get back a representation of the authenticated end user.</p>\n\n<h3>OpenID Connect UserInfo Endpoint</h3>\n\n<pre><code>https://authorization-server.com/userinfo\nAuthorization: Bearer XXXXX\n</code></pre>\n\n<pre><code>{\n \"sub\": \"https://aaronparecki.com/\",\n \"name\": \"Aaron Parecki\",\n \"email\": \"aaron@parecki.com\",\n \"preferred_username\": \"aaronpk\",\n ...\n}\n</code></pre>\n\n<p>This ends up looking very similar to the provider-specific endpoints that we looked at above.</p>\n\n<h3>OpenID Connect ID Tokens</h3>\n\n<p>The other way OpenID Connect deals with identity is by defining a new type of token, an \"ID token\". The ID token is defined as a JSON Web Token (JWT) that encodes the user's profile information. This ID token is then returned in response to an OpenID Connect request, either returned in the redirect URL using the <a href=\"https://oauth.net/2/grant-types/implicit/\">implicit flow</a>, or returned alongside the access token using the <a href=\"https://aaronparecki.com/%5Boauth.net/2/grant-types/authorization-code/%5D(https://oauth.net/2/grant-types/authorization-code/)(https://oauth.net/2/grant-types/authorization-code/)\">authorization code flow</a>.</p>\n\n<p>In the case of the implicit flow, the application that receives the ID token needs to validate the JWT signature and all the JWT claims, because otherwise anyone could drop an ID token into an application to be signed in. This is a standard part of the plain OpenID Connect workflow.</p>\n\n<p>Applications that also need an access token in addition to the ID token should be using the authorization code flow to obtain the access token, otherwise they are at risk of the <a href=\"https://developer.okta.com/blog/2019/05/01/is-the-oauth-implicit-flow-dead\">access token leaking</a>.</p>\n\n<p>So if an application is getting both an access token and ID token, the simplest way is to get both via the authorization code flow, so that both tokens end up being returned in the response to exchanging the authorization code at the token endpoint. This ends up looking like the below.</p>\n\n<pre><code>POST /token\nContent-type: application/x-www-form-urlencoded\n\ngrant_type=authorization_code\n&code=XXXXXXXXX\n&redirect_uri=https://example-app.com/redirect\n&client_id={CLIENT_ID}\n&client_secret={CLIENT_SECRET}\n</code></pre>\n\n<pre><code>{\n \"access_token\": \"SlBV32hkMG\",\n \"token_type\": \"Bearer\",\n \"expires_in\": 3600,\n \"refresh_token\": \"2xMBxBtEp3\",\n \"id_token\": \"eyJhbGciOiJSUzI1...\"\n}\n</code></pre>\n\n<p>The interesting part about this is that in this case, the ID token validation step <a href=\"https://developers.google.com/identity/protocols/OpenIDConnect#obtainuserinfo\">can be skipped</a> completely, since validating it would provide no additional benefit. The application already knows it's talking to the right server, it knows the response is coming from that server, and the connection can't be tampered with since it will be made over HTTPS. This means the application can just extract the data it needs from the ID token and use it directly.</p>\n\n<p>The problem with this approach is that this is essentially providing the application with a point-in-time snapshot of the user's profile information. If their profile information changes, there is no way for the application to get that update unless it either fetches the information from the userinfo endpoint or if the user signs in again. While this may only be a minor annoyance for things like the user's name, it is potentially dangerous for other profile information such as what groups a user belongs to, or other things the application may be relying on to modify its behavior based on the logged-in user.</p>\n\n<p>It also means that the entire profile information for the user is pushed to the application whether it needs it or not. And again, while this may not be a big deal if the only profile information sent is the user's name and email address, it can be potentially a lot of data such as groups, roles, or other provider-specific information that the authorization server may have about the user.</p>\n\n<h2>Identity in XYZ</h2>\n\n<p>While we're re-thinking OAuth from the ground up, we should also re-think how identity is handled within the system, while drawing from the experience of widely deployed systems. Rather than returning an ID token with potentially stale or large amounts of user information in the authorization response, let's return only the minimum necessary for the application to function, and let it request additional information that it needs when it needs it.</p>\n\n<h3>Transaction Request (Authorization Code Exchange)</h3>\n\n<p>In XYZ, the application takes the interact handle it got from the redirect and makes a POST request back to the authorization server to get an access token. (Described in <a href=\"https://aaronparecki.com/%5Boauth.xyz/transactionrequest/%5D(https://oauth.xyz/transactionrequest/)(https://oauth.xyz/transactionrequest/)\">Transaction Request</a>.)</p>\n\n<pre><code>POST /authorize\nContent-type: application/json\n\n{\n \"handle\": \"80UPWY2NM33OMUKMKSKU\",\n \"interact_handle\": \"CuD2MrpSXVKvvI6dN2awtNLx-HhZy46hJFDBicG4KoZaCmBofvqPxtm7CDMTsUFuvcmLwi_zUN70cCvalI6ENw\"\n}\n</code></pre>\n\n<p>We'll extend the response as described next.</p>\n\n<h3>Transaction Response (Access Token and User Identity)</h3>\n\n<p>In addition to the access token being returned, the user identifier can also be returned in the same response.</p>\n\n<p>The <a href=\"https://aaronparecki.com/%5Boauth.xyz/transactionresponse/%5D(https://oauth.xyz/transactionresponse/)(https://oauth.xyz/transactionresponse/)\">transaction response</a> can include just the unique user identifier along with the access token.</p>\n\n<pre><code>{\n \"access_token\": {\n \"value\": \"UM1P9PMHKUR64TB8N6BW7OZB8CDFONP219RP1LT0\",\n \"type\": \"bearer\"\n },\n \"user\": {\n \"id\": \"5035678642\"\n }\n}\n</code></pre>\n\n<p>This property is analogous to the \"sub\" property in an ID token. This value MUST uniquely identify this user within the system, and MUST be consistent when the same user logs in to the same application. The value MAY vary for the same user when logging in to different applications in order to preserve the user's privacy, preventing different applications from cross-correlating users between apps. (This is based on the deployed behavior of several APIs such as Facebook's \"app-scoped IDs\" and Apple's app-specific user ID and proxy email address.)</p>\n\n<p>If the application needs to know profile information about the user, it can get that from the userinfo endpoint using the access token it just obtained.</p>\n\n<p>We can go one step further and also return the userinfo endpoint at the same time as returning the user's unique identifier, avoiding the need for the app developer to hard-code this value in the app or find it in a separate discovery spec.</p>\n\n<pre><code>{\n \"access_token\": {\n \"value\": \"UM1P9PMHKUR64TB8N6BW7OZB8CDFONP219RP1LT0\",\n \"type\": \"bearer\"\n },\n \"user\": {\n \"id\": \"5035678642\",\n \"userinfo\": \"https://authorization-server.com/user/5035678642\"\n }\n}\n</code></pre>\n\n<p>This provides the additional advantage of the opportunity for the authorization server to use a unique URL per user if it wants (although that is by no means a requirement, since the access token will need to be included in the request too).</p>\n\n<p>If the application then wants to discover profile information about the user, it can make a request to the userinfo endpoint with the access token:</p>\n\n<pre><code>GET /user/5035678642\nAuthorization: Bearer UM1P9PMHKUR64TB8N6BW7OZB8CDFONP219RP1LT0\n</code></pre>\n\n<pre><code>{\n \"id\": \"5035678642\",\n \"name\": \"Aaron Parecki\",\n \"nickname\": \"aaronpk\",\n \"email\": \"aaron@parecki.com\",\n \"photo\": \"https://aaronparecki.com/images/profile.jpg\",\n \"zoneinfo\": \"America/Los_Angeles\"\n}\n</code></pre>\n\n<p>This ensures that the application knows that it can get the latest version of the user's profile information whenever it needs to by continuing to make requests to the userinfo endpoint, and prevents the temptation to treat the initial snapshot of the profile information as authoritative.</p>\n\n<p>If we don't address this need in XYZ, we'll risk ending up in the same situation we're in with OAuth 2.0 where providers end up implementing their own snowflake APIs to let apps find the user's profile information anyway.</p>"
},
"author": {
"type": "card",
"name": "Aaron Parecki",
"url": "https://aaronparecki.com/",
"photo": "https://aperture-media.p3k.io/aaronparecki.com/41061f9de825966faa22e9c42830e1d4a614a321213b4575b9488aa93f89817a.jpg"
},
"post-type": "article",
"_id": "4532258",
"_source": "16"
}
I guess now that the Twitter PWA has account switching, and social media at @mozhacks is not my primary responsibility anymore I could revisit switching to the PWA completely 🤔
Oh no, @Twitter. No no no no no.
On and off Twitter? Using my online and offline activity? And this is an FYI with no way to opt out? BIG FAT NO!
Switching to a third-...
{
"type": "entry",
"published": "2019-07-19T03:58:35+00:00",
"url": "https://twitter.com/slsoftworks/status/1152065169062649857",
"category": [
"https://twitter.com/mozhacks"
],
"quotation-of": "https://twitter.com/SaraSoueidan/status/1152059255878553600",
"content": {
"text": "I guess now that the Twitter PWA has account switching, and social media at @mozhacks is not my primary responsibility anymore I could revisit switching to the PWA completely \ud83e\udd14",
"html": "I guess now that the Twitter PWA has account switching, and social media at <a href=\"https://twitter.com/mozhacks\">@mozhacks</a> is not my primary responsibility anymore I could revisit switching to the PWA completely \ud83e\udd14"
},
"author": {
"type": "card",
"name": "flaki",
"url": "https://twitter.com/slsoftworks",
"photo": "https://aperture-proxy.p3k.io/6285144b4ec9009aa695015b76d5cdc404cd8fb6/68747470733a2f2f7062732e7477696d672e636f6d2f70726f66696c655f696d616765732f3734393637383638333531343839363338352f37677849526e6f432e6a7067"
},
"post-type": "note",
"refs": {
"https://twitter.com/mozhacks": {
"type": "card",
"name": "Mozilla Hacks",
"url": "https://twitter.com/mozhacks",
"photo": null
},
"https://twitter.com/SaraSoueidan/status/1152059255878553600": {
"type": "entry",
"published": "2019-07-19T03:35:05+00:00",
"url": "https://twitter.com/SaraSoueidan/status/1152059255878553600",
"category": [
"https://twitter.com/Twitter"
],
"photo": [
"https://pbs.twimg.com/media/D_zvyDIU0AAIFYe.jpg"
],
"content": {
"text": "Oh no, @Twitter. No no no no no. \n\nOn and off Twitter? Using my online and offline activity? And this is an FYI with no way to opt out? BIG FAT NO!\n\nSwitching to a third-party app _right now_.",
"html": "Oh no, <a href=\"https://twitter.com/Twitter\">@Twitter</a>. No no no no no. \n\nOn and off Twitter? Using my online and offline activity? And this is an FYI with no way to opt out? BIG FAT NO!\n\nSwitching to a third-party app _right now_."
},
"author": {
"type": "card",
"name": "Sara Soueidan",
"url": "https://twitter.com/SaraSoueidan",
"photo": "https://pbs.twimg.com/profile_images/1010126354078208001/MpkO7-qK.jpg"
},
"post-type": "photo",
"refs": {
"https://twitter.com/Twitter": {
"type": "card",
"name": "Twitter",
"url": "https://twitter.com/Twitter",
"photo": null
}
}
}
},
"_id": "4532089",
"_source": "2773"
}
okay time to play a sim game instead of watchdogs because I can't grasp games like that tbh
{
"type": "entry",
"published": "2019-07-19T03:53:24+00:00",
"url": "https://twitter.com/jackyalcine/status/1152063864697061377",
"content": {
"text": "okay time to play a sim game instead of watchdogs because I can't grasp games like that tbh"
},
"author": {
"type": "card",
"name": "Jacky Alcin\u00e9",
"url": "https://twitter.com/jackyalcine",
"photo": "https://aperture-proxy.p3k.io/af89865555b71ab66d185400dd43a315963ddf76/68747470733a2f2f7062732e7477696d672e636f6d2f70726f66696c655f696d616765732f313135313532303433303839383837323332302f4a656259646c336e2e6a7067"
},
"post-type": "note",
"_id": "4532007",
"_source": "2773"
}
I work with @zspencer a lot and enjoy every moment! I’d strongly recommend him for those looking for an engineering coach! https://t.co/eMl28rPBpn (v2.jacky.wtf/post/58c03d6e-…)
Heads up eng managers/directors! I am looking for someone to book one or two ~4 hour pair programming sessions per week for the next few quarters.
If you have people on ...
{
"type": "entry",
"published": "2019-07-19T03:39:46+00:00",
"url": "https://twitter.com/jackyalcine/status/1152060436344213505",
"category": [
"https://twitter.com/zspencer"
],
"quotation-of": "https://twitter.com/zspencer/status/1151980422424752128",
"content": {
"text": "I work with @zspencer a lot and enjoy every moment! I\u2019d strongly recommend him for those looking for an engineering coach! https://t.co/eMl28rPBpn (v2.jacky.wtf/post/58c03d6e-\u2026)",
"html": "I work with <a href=\"https://twitter.com/zspencer\">@zspencer</a> a lot and enjoy every moment! I\u2019d strongly recommend him for those looking for an engineering coach! https://t.co/eMl28rPBpn (<a href=\"https://v2.jacky.wtf/post/58c03d6e-3172-4ede-b169-13a1c41cf3d7\">v2.jacky.wtf/post/58c03d6e-\u2026</a>)"
},
"author": {
"type": "card",
"name": "Jacky Alcin\u00e9",
"url": "https://twitter.com/jackyalcine",
"photo": "https://aperture-proxy.p3k.io/af89865555b71ab66d185400dd43a315963ddf76/68747470733a2f2f7062732e7477696d672e636f6d2f70726f66696c655f696d616765732f313135313532303433303839383837323332302f4a656259646c336e2e6a7067"
},
"post-type": "note",
"refs": {
"https://twitter.com/zspencer": {
"type": "card",
"name": "Zee (He/Him)",
"url": "https://twitter.com/zspencer",
"photo": null
},
"https://twitter.com/zspencer/status/1151980422424752128": {
"type": "entry",
"published": "2019-07-18T22:21:50+00:00",
"url": "https://twitter.com/zspencer/status/1151980422424752128",
"content": {
"text": "Heads up eng managers/directors! I am looking for someone to book one or two ~4 hour pair programming sessions per week for the next few quarters.\n\nIf you have people on your team that you think are good and could be _great_ with a bit of direct technical coaching, hit me up."
},
"author": {
"type": "card",
"name": "Zee (He/Him)",
"url": "https://twitter.com/zspencer",
"photo": "https://pbs.twimg.com/profile_images/540237689392361472/f96ILqGI.jpeg"
},
"post-type": "note"
}
},
"_id": "4531914",
"_source": "2773"
}
Going to retire the mentality of ‘asking for forgiveness instead of permission’ from my life. Noticing that it’s encouraging an abusive behavior of ignoring boundaries versus working with and adhering to them. (v2.jacky.wtf/post/e35b63d4-…)
{
"type": "entry",
"published": "2019-07-19T03:35:27+00:00",
"url": "https://twitter.com/jackyalcine/status/1152059349776441344",
"content": {
"text": "Going to retire the mentality of \u2018asking for forgiveness instead of permission\u2019 from my life. Noticing that it\u2019s encouraging an abusive behavior of ignoring boundaries versus working with and adhering to them. (v2.jacky.wtf/post/e35b63d4-\u2026)",
"html": "Going to retire the mentality of \u2018asking for forgiveness instead of permission\u2019 from my life. Noticing that it\u2019s encouraging an abusive behavior of ignoring boundaries versus working with and adhering to them. (<a href=\"https://v2.jacky.wtf/post/e35b63d4-4053-432a-8f26-5065339f975e\">v2.jacky.wtf/post/e35b63d4-\u2026</a>)"
},
"author": {
"type": "card",
"name": "Jacky Alcin\u00e9",
"url": "https://twitter.com/jackyalcine",
"photo": "https://aperture-proxy.p3k.io/af89865555b71ab66d185400dd43a315963ddf76/68747470733a2f2f7062732e7477696d672e636f6d2f70726f66696c655f696d616765732f313135313532303433303839383837323332302f4a656259646c336e2e6a7067"
},
"post-type": "note",
"_id": "4531915",
"_source": "2773"
}
I work with @zspencer a lot and enjoy every moment! I’d strongly recommend him for those looking for an engineering coach! https://twitter.com/zspencer/status/1151980422424752128
{
"type": "entry",
"published": "2019-07-18T20:39:44.26950-07:00",
"url": "https://v2.jacky.wtf/post/58c03d6e-3172-4ede-b169-13a1c41cf3d7",
"content": {
"text": "I work with @zspencer a lot and enjoy every moment! I\u2019d strongly recommend him for those looking for an engineering coach! https://twitter.com/zspencer/status/1151980422424752128",
"html": "<p>I work with <a href=\"https://twitter.com/zspencer\">@zspencer</a> a lot and enjoy every moment! I\u2019d strongly recommend him for those looking for an engineering coach! <a href=\"https://twitter.com/zspencer/status/1151980422424752128\">https://twitter.com/zspencer/status/1151980422424752128</a></p>"
},
"author": {
"type": "card",
"name": "Jacky Alcin\u00e9",
"url": "https://v2.jacky.wtf",
"photo": "https://aperture-proxy.p3k.io/9f6c6c125a7640abc3c67f876753b4bf233d06d6/68747470733a2f2f76322e6a61636b792e7774662f6d656469612f70726f66696c652d696d616765"
},
"post-type": "note",
"_id": "4531891",
"_source": "1886"
}
Going to retire the mentality of ‘asking for forgiveness instead of permission’ from my life. Noticing that it’s encouraging an abusive behavior of ignoring boundaries versus working with and adhering to them.
{
"type": "entry",
"published": "2019-07-18T20:35:25.63808-07:00",
"url": "https://v2.jacky.wtf/post/e35b63d4-4053-432a-8f26-5065339f975e",
"content": {
"text": "Going to retire the mentality of \u2018asking for forgiveness instead of permission\u2019 from my life. Noticing that it\u2019s encouraging an abusive behavior of ignoring boundaries versus working with and adhering to them.",
"html": "<p>Going to retire the mentality of \u2018asking for forgiveness instead of permission\u2019 from my life. Noticing that it\u2019s encouraging an abusive behavior of ignoring boundaries versus working with and adhering to them.</p>"
},
"author": {
"type": "card",
"name": "Jacky Alcin\u00e9",
"url": "https://v2.jacky.wtf",
"photo": "https://aperture-proxy.p3k.io/9f6c6c125a7640abc3c67f876753b4bf233d06d6/68747470733a2f2f76322e6a61636b792e7774662f6d656469612f70726f66696c652d696d616765"
},
"post-type": "note",
"_id": "4531867",
"_source": "1886"
}
Lanterns Dice in KC! (at @KiloCharlieHp in Kansas City, MO) swarmapp.com/c/4mvsDNgE1UB
{
"type": "entry",
"published": "2019-07-19T03:04:48+00:00",
"url": "https://twitter.com/afitnerd/status/1152051636597952513",
"category": [
"https://twitter.com/KiloCharlieHP"
],
"photo": [
"https://aperture-proxy.p3k.io/cce4fd843e7f65a2da053c433c1f34f17962f102/68747470733a2f2f7062732e7477696d672e636f6d2f6d656469612f445f7a6f32386856554141504c58342e6a7067"
],
"content": {
"text": "Lanterns Dice in KC! (at @KiloCharlieHp in Kansas City, MO) swarmapp.com/c/4mvsDNgE1UB",
"html": "Lanterns Dice in KC! (at <a href=\"https://twitter.com/KiloCharlieHP\">@KiloCharlieHp</a> in Kansas City, MO) <a href=\"https://www.swarmapp.com/c/4mvsDNgE1UB\">swarmapp.com/c/4mvsDNgE1UB</a>"
},
"author": {
"type": "card",
"name": "Micah Silverman",
"url": "https://twitter.com/afitnerd",
"photo": "https://aperture-proxy.p3k.io/7fe25b1c5d3b48ffef367bc234b98fce3c05fb58/68747470733a2f2f7062732e7477696d672e636f6d2f70726f66696c655f696d616765732f3337383830303030303431393432323831382f34643361376235393834333431313065663361306434346639363831373138352e6a706567"
},
"post-type": "photo",
"refs": {
"https://twitter.com/KiloCharlieHP": {
"type": "card",
"name": "Kilo Charlie",
"url": "https://twitter.com/KiloCharlieHP",
"photo": null
},
"https://aperture-proxy.p3k.io/cce4fd843e7f65a2da053c433c1f34f17962f102/68747470733a2f2f7062732e7477696d672e636f6d2f6d656469612f445f7a6f32386856554141504c58342e6a7067": {
"type": "image",
"ratio": 1.33,
"bytes": 199320
}
},
"_id": "4531535",
"_source": "2773"
}
Lmfaoooo I say this as a joke but seeing someone else say this is low-key scary. Like are you an evolved NPC?! https://t.co/VBIBaRUrLD (v2.jacky.wtf/post/a6b8c8e9-…)
Bro people really be NPCs 😦
{
"type": "entry",
"published": "2019-07-19T03:00:43+00:00",
"url": "https://twitter.com/jackyalcine/status/1152050606749696003",
"quotation-of": "https://twitter.com/Winnatina/status/1152045622817689603",
"content": {
"text": "Lmfaoooo I say this as a joke but seeing someone else say this is low-key scary. Like are you an evolved NPC?! https://t.co/VBIBaRUrLD (v2.jacky.wtf/post/a6b8c8e9-\u2026)",
"html": "Lmfaoooo I say this as a joke but seeing someone else say this is low-key scary. Like are you an evolved NPC?! https://t.co/VBIBaRUrLD (<a href=\"https://v2.jacky.wtf/post/a6b8c8e9-b291-4698-8f31-98aabd034c5f\">v2.jacky.wtf/post/a6b8c8e9-\u2026</a>)"
},
"author": {
"type": "card",
"name": "Jacky Alcin\u00e9",
"url": "https://twitter.com/jackyalcine",
"photo": "https://aperture-proxy.p3k.io/af89865555b71ab66d185400dd43a315963ddf76/68747470733a2f2f7062732e7477696d672e636f6d2f70726f66696c655f696d616765732f313135313532303433303839383837323332302f4a656259646c336e2e6a7067"
},
"post-type": "note",
"refs": {
"https://twitter.com/Winnatina/status/1152045622817689603": {
"type": "entry",
"published": "2019-07-19T02:40:55+00:00",
"url": "https://twitter.com/Winnatina/status/1152045622817689603",
"content": {
"text": "Bro people really be NPCs \ud83d\ude26"
},
"author": {
"type": "card",
"name": "Nicatina",
"url": "https://twitter.com/Winnatina",
"photo": "https://pbs.twimg.com/profile_images/1110071964041969664/W6PFoiMl.jpg"
},
"post-type": "note"
}
},
"_id": "4531536",
"_source": "2773"
}
Oregon beach sunset at the end of a delightful vacation day. Coming to appreciate the meaning of "carefree".
Also on: Instagram
{
"type": "entry",
"author": {
"name": "David Bryant",
"url": "https://orangemoose.com/blog",
"photo": null
},
"url": "https://orangemoose.com/blog/2019/07/17/215/",
"published": "2019-07-17T07:18:44-07:00",
"content": {
"html": "<a href=\"https://orangemoose.com/blog/2019/07/17/215/iguwdqtj/\"><img src=\"https://aperture-proxy.p3k.io/1caf32cd0a9285d81bcf951c16e989bede4ef9ac/68747470733a2f2f6f72616e67656d6f6f73652e636f6d2f626c6f672f77702d636f6e74656e742f75706c6f6164732f323031392f30372f696775774471546a2d31303234783738362e6a7067\" alt=\"\" /></a>\n<p>Oregon beach sunset at the end of a delightful vacation day. Coming to appreciate the meaning of \"carefree\".</p>\nAlso on:<p><a href=\"https://www.instagram.com/p/B0BV1GdpG8G/\"> Instagram</a></p>",
"text": "Oregon beach sunset at the end of a delightful vacation day. Coming to appreciate the meaning of \"carefree\".\nAlso on: Instagram"
},
"post-type": "note",
"_id": "4531526",
"_source": "2934"
}
Room service Father’s Day treat ordered up for me by Michael and Camille (from far away). I sure do have marvelous kids! Love you both, always.
Also on: Instagram
{
"type": "entry",
"author": {
"name": "David Bryant",
"url": "https://orangemoose.com/blog",
"photo": null
},
"url": "https://orangemoose.com/blog/2019/06/16/217/",
"published": "2019-06-16T15:41:18-07:00",
"content": {
"html": "<a href=\"https://orangemoose.com/blog/2019/06/16/217/igjhnh3n/\"><img src=\"https://aperture-proxy.p3k.io/06619ecc0c11a6fc5e519820313992741400c7cc/68747470733a2f2f6f72616e67656d6f6f73652e636f6d2f626c6f672f77702d636f6e74656e742f75706c6f6164732f323031392f30372f69676a484e48336e2d3130323478313032342e6a7067\" alt=\"\" /></a>\n<p>Room service Father\u2019s Day treat ordered up for me by Michael and Camille (from far away). I sure do have marvelous kids! Love you both, always.</p>\nAlso on:<p><a href=\"https://www.instagram.com/p/Byyas52Cz7q/\"> Instagram</a></p>",
"text": "Room service Father\u2019s Day treat ordered up for me by Michael and Camille (from far away). I sure do have marvelous kids! Love you both, always.\nAlso on: Instagram"
},
"post-type": "note",
"_id": "4531527",
"_source": "2934"
}
Lmfaoooo I say this as a joke but seeing someone else say this is low-key scary. Like are you an evolved NPC?! https://twitter.com/Winnatina/status/1152045622817689603
{
"type": "entry",
"published": "2019-07-18T20:00:00.00000-07:00",
"url": "https://v2.jacky.wtf/post/a6b8c8e9-b291-4698-8f31-98aabd034c5f",
"content": {
"text": "Lmfaoooo I say this as a joke but seeing someone else say this is low-key scary. Like are you an evolved NPC?! https://twitter.com/Winnatina/status/1152045622817689603",
"html": "<p>Lmfaoooo I say this as a joke but seeing someone else say this is low-key scary. Like are you an evolved NPC?! <a href=\"https://twitter.com/Winnatina/status/1152045622817689603\">https://twitter.com/Winnatina/status/1152045622817689603</a></p>"
},
"author": {
"type": "card",
"name": "Jacky Alcin\u00e9",
"url": "https://v2.jacky.wtf",
"photo": "https://aperture-proxy.p3k.io/9f6c6c125a7640abc3c67f876753b4bf233d06d6/68747470733a2f2f76322e6a61636b792e7774662f6d656469612f70726f66696c652d696d616765"
},
"post-type": "note",
"_id": "4531495",
"_source": "1886"
}