#[KevinMarks]twitter no longer has hcards for contacts, technorati no longer has the hcard to vcard converter, plaxo no longer converts vcards to portable contacts, and jsontoxoxo is now on unmung
#Loqi[DoctorMac] @lukeboch and @manton I asked on indieweb chat. You could use unmung to turn the rss feed into an html feed and then granary.io to turn hfeed into json feed....I betchya results somewhere from broken to ugly but worth a shot
#[jgmac1106]ugg used the wrong browser to start, I handle multiple identities on microblog by using different browsers
#[jgmac1106]nobody in their right mind wants to read about NIST controls all day...been driving me crazy
#barnabySaphire: yes, that’s correct, as IA is defined right now, the authorization endpoint needs to implement both a user-facing authorization flow, and an app-facing auth code redeeming flow
#barnabyit adds some complexity as the user-facing stuff must be CSRF-protected, but not the app-facing stuff
#barnabyit’s a back-compat thing held over from older versions of indieauth, and is not compatible with OAuth2. there’s been some discussion about deprecating it, but for the moment it’s still part of the spec
#SaphireBecause holy fuck trying to implement that in something that isn't PHP, Lua or other kind of dynamic language just kinda hurts
#barnabywell depending on your needs, you can choose to pre-emptively deprecate it yourself :) I don’t think there’s a list of which clients rely on that feature
#barnaby(I have a sneaking suspicion that the indieweb wiki might be one)
#barnabyfwiw I just mostly finished implementing it in heavily-type-annotated PHP, and it wasn’t too bad
#barnabyhave a function which accepts an HTTP request object and returns an HTTP response. if the request is an auth code redeeming request, pass it off to the auth token redeeming logic. otherwise, pass it off to the authorization flow logic, wrapped in a CSRF middleware
#Loqi[aaronpk] #58 Allow clients to always exchange authorization codes at the token endpoint
#ZegnatI am not sure about the “not compatible with OAuth2” though. Why do you think that, barnaby? That would be a great reason to deprecate it ASAP too. But as I understand it, OAuth2 does not specify any preferences as far as which endpoints do what, and it is completely fine even to have auth and token endpoint be the exact same URL always.
#barnabyoh okay, that might be me misunderstanding OAuth2 then
#barnabyI admit that I’ve not read the entire OAuth2 spec, but interpreted the first paragraph of that issue you linked as IA not being compatible/compliant/consistent due to a) allowing empty scope and b) allowing access tokens to be redeemed at the authorization endpoint
#barnabyin other news, my WIP IA library’s auth endpoint has 92% code coverage!
#Loqi[Zegnat] #62 Clarification on issueing token with profile scope
#ZegnatOr well, not super confusing I was there for a lot of the spec writing talks, but maybe not super clear on the whole different-scopes-different-endpoints thing
#SaphireWhy was that not deprecated when /token was added? >->
#barnabyI think the auth endpoint scopeless token redeeming was kept in a) for back-compatbility and b) because people wanting to have a server which just authenticates them, and doesn’t grant a token, is quite a common use-case
#barnabysay for example you have a personal site, want to be able to log in with it, but don’t have a micropub endpoint
#barnabyregarding the set of queries, let me stub a list on the wiki, as it’s all in my head right now anyway
#barnabyhmm where would be the best place to put this
#barnabyso, the token_endpoint only has one flow, a POST request with authorization code details, which get verified. It returns a JSON response containing either access token details, or an error
#barnabythe authorization_endpoint has three potential flows (per the current spec):
#barnabya flow similar to the token_endpoint code redeeming flow, i.e. a POST request with auth code which results in a JSON response
#barnabyan authorization request flow, which is a GET request which the user was redirected to from their client app. the query string contains various parameters pertaining to the request. This flow needs to check that the user is logged in, redirect them to a login flow if not, and then finally return a consent/scope-granting form response on a logged-in request
#barnabythe final flow is a POST request containing the consent/scope-granting form submission, which needs to check validity, build an access_code and return a redirect back to the client app’s redirect_uri with code and state details
#barnaby(technically, the final flow could potentially be implemented at a different endpoint if you want, but I found it easiest to just re-use the authorization endpoint for it)
#barnabythe latter two flows MUST be CSRF-protected, the first flow cannot be
#SaphireBut yeah I'm trying to implement it in a very type safe language. And it's very, very easy to make an endpoint that will take in a specific object constructed from params
#SaphireExcept that.. in this case this object would be actually multiple ones blended together and the function would be a scary two/three way thing?
#barnabyultimately the top-level endpoint code needs to accept some sort of HTTP Request object, and return an HTTP response
#barnabyand then within that, you detect the nature of the response, maybe build a query object from the HTTPRequest specific to the detected flow, and pass that off to a dedicated function
#barnabyI implemented it in PHP, but I didn’t use any dynamic features which aren’t available in, e.g. rust
#barnabyI do have one callback function which can choose to return either a pre-made HTTPResponse object or authentication data, but in rust I would just use an enum and it’d be totally type-safe
#SaphireIt's less "impossible" and more "this gets ugly fast"
#barnabyyeah, there’s a fair amount of state to keep track of, and complications with handing a logged-out request off to a login route and then seamlessly restarting the indieauth request
#barnabyI spent a few hours reading the spec and scribbling diagrams on paper before I felt like I understood it well enough to start writing code
#barnabyalso IMO there’s a bunch of stuff on that page which has little to do with the auth endpoint and needs to either be removed or clarified, e.g. the stuff about the sign-in form
#barnabysure, that’s how a user gets to the auth endpoint, but it’s not part of the auth endpoint implementation
#sknebelsome rumors they were rolling out code for Apple's new "VPN" and that broke
#Zegnatbarnaby: I am not sure if I agree with "consent form submission" as a flow. That is an implementation detail, and is also why it is not included in the spec (or in any OAuth spec).
#barnabyZegnat: sure, it’s not included in the spec, and that’s one of the reasons why the spec doesn’t work as an implementation guide
#barnabythere’s not much point having /authorization_endpoint just repeat what’s in the spec. IMO it’s better put to use as a practical implementation guide
#ZegnatThe only two flows that MUST be supported are accepting a GET request that (in happy flow) results in a redirect back, and accepting a POST request that (in happy flow) results in a Profile URL Response
#barnabyyeah but in practise, an auth endpoint will most likely have an intermediary consent form
hendursa1 joined the channel
#Zegnatbarnaby: I agree , for implementation guide. I just wanted to be a stickler and point out that there are really only 2 possible incoming requests that you MUST support for the spec. And those two can actually be split based on HTTP method already and you do not need to inspect parameters for it
#ZegnatIt is for instance completely fine (if it is easier for the implementation) to redirect the user to an entirely different endpoint for showing the consent form.
#mgdmFastly's official line is "We experienced a global outage due to an undiscovered software bug that surfaced on June 8 when it was triggered by a valid customer configuration change."
#barnabyZegnat, yeah, that’d be a good addition to the list of flows
#ZegnatSo if, completely hypothetical because I do not know, Saphire’s problem is with inspecting query params, it is completely fine to skip that entirely. Check if the incoming request to the authorization endpoint is a GET or a POST, after that you know exactly what the possible set of parameters is.
#barnabyZegnat: true, but only if your consent form submits a POST request to a separate endpoint
#ZegnatThe consent form could be fully JS based for all I know, and talk with an endpoint on an entire different domain. That is why I do not like to generalise about it, and is why OAuth makes it an implementation detai
#barnabyalso, while it is in theory currently possible to determine which flow is happening based on the method, in practise it’s also necessary to inspect the query params (response_type=code, specifically)
#Zegnat? Not really? If you are doing a GET, you can assume that response_type=code is set. In fact, you should immediately stop the process if it is not.
#SaphireZegnat: so authenticated vs non-authenticated..
#SaphireFormer has a `code` query param, the other doesn't?
#barnabyexactly, you need to check the response_type parameter to make sure it’s a valid request
#ZegnatSo you can make the call based on HTTP method, if it is a GET, you probably want to validate the params so you can exit early if it is not a valid OAuth request, but at that point you have already determined the type of request based on the method. (Which I thought the issue here was.)
#SaphireOr wait, was that an implementation detail
#SaphireAuthenticated /on the auth endpoint end/, or on client end?
#ZegnatWhen a client makes a GET request against the authorization endpoint, it expects to be redirected back to a URL it provided in that GET request. Any pages (or none) you chose to show in between is up to you.
#ZegnatWhen a client makes a POST request against the authorization endpoint, it expects a Profile URL response per the spec back.
#ZegnatThose are the only two MUST cases for an authorization endpoint.
#barnabyyep, which is described well by the spec, but at /authorization-endpoint I want to help people actually build practical endpoints, which involves some non-generic implementation details
#barnabydetails which, per my and Saphire’s experiences, are not currently well described anywhere easily discoverable
#ZegnatYeah, I can see how that is not really clear everywhere. I guess I am just a stickler on the fact that none of those details should be covered by the IndieAuth spec (wich is an extension to OAuth 2.0) because it can and will vary wildly between platforms.
#ZegnatI think that node one is based on the PHP selfauth one. It uses the exact same logic for checking state values, with the exact same function names, haha
#ZegnatI wonder why it does that. It is not good code. We used md5 as a lowest common denominator for old PHP versions. Node.js should have been able to do better
#ZegnatOr well, the code is fine, but it is far from as secure as can be
#barnabythat’s the danger of writing for the lowest common denominator — other people might take it as a reference implementation ;)
#Zegnatbarnaby: PHP one does that too. But that might have been because the signed codes part that adds time-to-live was added later and we did not want to break existing setups with md5 passwords.
#Zegnatselfauth has done pretty well as a reference implementation for people, I believe. And most of the error checking is super solid. But for the actual hashing stuff it is showing its age
#ZegnatThe part that there were 2 different flows for authentication and authorization is why we are stuck with authorization endpoint having to handle code exchanges
#ZegnatMy current implementation is more comments than code, hahaha
#Loqi[Zegnat] php-mintoken: A minimal IndieAuth compatible Token Endpoint.
#ZegnatNote that it is an implementation of an older spec version though. As it needs to be able to contact the authorization endpoint to see if a token should be issued
#barnaby"sqlite3 tokens.db < schema.sql" < now that’s a dbadmin approach I can live with ;)
#ZegnatI could do a whole script for initialising a database and prepping the tables … oooor I can just ask people to run that :D
#sknebelwe probably should update selfauth to match what currently supported PHP versions can do
#SaphireSo for security uh. I should only let the GET /auth_endpoint to only redirect to actual page, one which is set to Allow-Origin only of the auth site?
#barnabybut if md5 is just there to support existing hashed passwords then I guess that doesn’t apply
#ZegnatBut only for newer features, as older features were jsut not touched anymore, haha.
#SaphireAnd have a token supplied to that page that can be verified later?
#ZegnatSaphire: I am not sure I follow. On submission of consent is when you would generate a code and redirect to user back to the original client.
#SaphireSo it goes.. client -> /auth_endpoint with query of {me, redirect_url, client_id, ...}, Then auth endpoint does a redirect or in any other way goes through an authentication and authorization flow, the entire flow resulting (on success) in redirect to redirect_url and query params of code and state, where state is original state supplied to endpoint and code is an opaque token that can be
#barnabyand the opaque token can be exchanged either for profile information (at the auth endpoint) or an access token (at the token endpoint)
#Saphire...and a separate flow of {code, redirect_url, client_id} to same endpoint where it checks the token (in opaque way) and just goes nah, or ok and gives user info?
#ZegnatIf this POST went to the authorization endpoint it will result in either HTTP 200 response with a JSON body { me[, profile] } or HTTP 400 with a JSON body according to OAuth rfc 6749 with error information
#barnabyhmm okay I need to figure out if that will cause problems for my implementation
#barnabyhopefully “client requests” only refers to requests sent to/redirected to the client app
#barnabyhopefully “client requests” only refers to requests sent to/redirected to the client app
#ZegnatI am not sure I follow. Sorry. Some of this stuff might just be super obvious to me because I have been involved from the get go :P
#Zegnatcode_verifier is only sent once, by the client, when they go and exchange the code for a token (or for profile information).
#ZegnatClients have to keep it an absolute secret until that point.
#ZegnatFor stateless clients, you can store it inside the "state" value, but in that case have to make sure it cannot be extracted from it, e.g. by encrypting the state payload
#barnabyso, my server library currently includes an unencrypted form of the code_challenge in any intermediate requests during the authentication and consent screen flow
#barnabyit wouldn’t be too much work to rework it, but I was happy with it the way it was :D
#ZegnatThey probably mean that you should not put the challenge next to the code, as the point of the challenge is that only the original requestee knows which code goes with which challenge and you want to keep it that way
#aaronpkand also from earlier, I am all in favor of making the wiki pages more of an implementation guide, calling out things that aren't appropriate to put in the actual spec. but it would also be useful to highlight that those things are still implementation details
#barnabyagreed, I tried to amend my flow descriptions to add that
#barnabymaybe have a “strict flows according to the spec”, and “practical suggestions for flows including authentication and consent screen details”
#barnabyso that there’s a summary of both on the same page, and so that there’s a structure for adding alternative implementation-specific flow suggestions which still comply with the general spec flow
#SaphireStrict flow according to spec leaves a lot of areas "up to implementer's imagination" basically v:
chenghiz_ joined the channel
#ZegnatThat is because the spec is there to normalise the traffic between the client and the server. Not the client or the server internals.
#ZegnatJust when servers are on the web, and the front-facing part of authentication and consent screen are handled by them, it starts to blur the lines a little, as the majority of the people implementing the server side of the spec will also need to implement all those unspeced things
#barnabyyeah, I ended up thinking of the spec as being written from the client’s point of view
[Murray] joined the channel
#ZegnatThat might be a more illustrative way of thinking, yes. It is definitely laid out that way. Though you can read it as the server’s point of view by treating the spec as being “in the likely order of requests send to me by a client”
#SaphireI kinda need to get indieauth working on my site to get to wiki, oooor remove the <link>s for indieauth leading to nothing. Actually invalid nothing, even
#SaphireI am assuming that authorization_endpoint returned code is basically just a temporary opaque thing (that is sufficiently non-predictable to not let people guess it!) that only lives for like, a minute or something?
#Saphire...and while it CAN be implemented basically through same stuff as a full token, you also can uh
#SaphireJust have a small runtime-only storage for those and clear it out from old stuff every so often?
#barnabyand according to the spec it MUST only be usable once, which means you either have to persist them somewhere and delete/expire them after they’re exchanged, OR keep track of which ones have been exchanged in your list of access tokens and check against that
#Saphire(as to not let your generous timeout of 5 minutes to let someone do hundreds of tokens for someone's account)
#SaphireBuuut you can have a small vector/table/object/etc in your persistently running server app (unless you are on something more per-request like PHP where you'll need to use a DB or other value store) that would be cleaned out from say, entries older than 5 minutes
#SaphireAnd only give tokens out for codes that are in that storage?
#Saphire(obviously store the challenge next to the codes, IF challenge is available)
#Saphire...I guess internally just have ChallengeType None v:
#ZegnatI think that is something like how I do it, I would have to double check. I actually store the one-time opaque codes in the db, and have all the important client details associated with it.
#ZegnatWhen the client then comes to exchange the code for a token, that token is added to the same database record, turning the code storage into a token storage. Codes are automatically one-time-use, because on second try I see the token field is already filled.
#ZegnatIt also makes it so all the client information that I got when the code is first requested is automatically associated with the issued token.
#ZegnatOne single db then gives me full tracing: when was a code created, when was it exchanged for a token (if at all), which client did it …
#ZegnatThe stateless way is what the previously linked endpoints do, where they put all that information into the code itself encoded/signed/encrypted in some way. Which is also fine, but I found that to be more overhead in the longrun than depending on an SQLite file
#barnabyand then you periodically purge expired records which never got exchanged for an access_token?
hendursaga joined the channel
#barnabythe stateless approach is nice but it doesn’t strictly comply with the requirement that access tokens must be only redeemable once, right?
#ZegnatWell, if both your codes and your tokens are stateless.
#barnabyyeah, exactly. at least one of them has to be stateful
#ZegnatIf you only want the codes to be stateless, but tokens are actually stored, you can always store the code on token generation
#ZegnatI think some applications just bite the bullet on that if they must be stateless. So they set a short TTL on the code and assume that to be reliable enough *shrug*
#barnabyyeah IMO it’s not necessary to comply strictly for most people, if the TTLs are small enough
#barnabybut when making a library I want to ensure that at least defaults to strict spec-compliance
#Saphire...can you reuse the auth code as part of info within a token?
#ZegnatAs long as the code can only have been generated by you (because it ensures the user has consented) it can be anything. Randomness is not a concern.
#SaphireBut you.. still have to check at least for the token being valid
#sknebelright. which is why I think for personal sites it doesn't matter
#SaphireAt which point properly secure stateless token ends up being just plain db optimization at most
#sknebelfor large systems there is some argument that it might be easier to keep and check a small revocation list on each node than always querying a DB of all tokens
#sknebel(stateless can still revoke *all* tokens by rotating the signing key)
#sknebelbut for what I'm doing I dont care about the small cost of a lookup
#ZegnatStateless always sounds fun when it is described as “look mum, no datatabase”, but then when you actually start implementing a full authorization flow and find out you need to bring in encryption to hide things from clients, keep track of ttls, etc., it is no longer as fun ;)
#sknebelI do "look mum, no database, just file system" :P
#SaphireAnd then you ask yourself "how do I keep tokens that are leaked from being abused?"
#SaphireAnd realize the entire damn thing is silly because you still end up tracking everything
#Saphire> Using a common data format allows for easy interoperability with established solutions. It is perfectly fine to develop your own token solution (as long as you don’t roll your own crypto). However, JWTs are the established solution, and you can’t go wrong with them.
#SaphireWonder what are the statistics for the auth on indieweb?
#ZegnatSpecifically on indieweb.org ? aaronpk might have those. Or maybe not. We are pretty statistics-lite in general on IndieWeb things. Wouldn’t want to do too much tracking
#SaphireLike, how many people are using the indieauth service vs having their own endpoint
IWSlackGateway and [tantek] joined the channel
#[tantek]hey snarfed, does granary support consuming h-feed h-entry u-featured images and converting them to some equivalent in Atom? That is, how do you publish featured images in Atom? perhaps <entry><link rel="featured" href="image.jpg" /> ?
#Loqifeatured is a proposed mf2 property (typically as u-featured) for h-entry that indicates a representative image for a post https://indieweb.org/featured
#[tantek]somewhat related, are folks using any kind of markup to express their "related posts" or "related articles" that they link to from a specific article/post?
shoesNsocks joined the channel
#[tantek]e.g. the "obvious" "simple" thing in plain HTML would be rel="related", but I'm not sure that's the best for structure inside an h-entry. I could see a u-related-entry property, but wanted to first check to see what people's existing publishing did.
#[tantek]or if other formats have something already, e.g. does Atom have a notion of <link rel="related" href="article.html" /> that you could put inside an <entry> ?
#[tantek]it's too bad the atom:icon element is only specified as a child of <feed>, missed opportunity there to re-use that for <entry> as a way to do a featured/preview image for an entry
[Murray], shoesNsocks and [snarfed] joined the channel
#[snarfed][tantek] yes! granary supports u-featured. doesn’t do anything special though, just includes them as picture attachments along with u-photos
#[snarfed]in Atom, they end up both as enclosures and rendered HTML in the content
#[tantek]snarfed, would it be worth exploring <link rel="featured"> in Atom? or not enough other consuming code to care?
#[tantek]something to distinguish from other enclosures
#[tantek]also curious about your thoughts about marking up "related posts" per above ^
gRegor joined the channel
#[snarfed]sure! I’m open to all of those. I don’t really follow a lot of markup semantics like those, so I’m probably not the best person to lead any changes, but I’m happy to review and merge!
[schmarty] and [KevinMarks] joined the channel
#[KevinMarks]mastodon's Atom feeds had a bunch of extra namespace stuff from PoCo to do author iirc
barnaby joined the channel
#[KevinMarks]though they dropped Atom and now have less expressive RSS
alex11 joined the channel
#[tantek][KevinMarks] speaking of Author in Atom, do you know any Atom feeds that publish author & publisher info in their markup?
#[tantek]Atom seems to lack something for publisher explicitly
[Ana_Rodrigues] joined the channel
#[tantek]closest hack might be to use atom:contributor element, with a uri, and then if that uri prefix matches the permalink of the entry, then that contributor can be determined to be the "publisher"
#barnabyis this theoretical, or do you have an atom feed where you want to provide separate publisher and author info?
#[tantek][KevinMarks] newspaper sites predate Atom. I'm kinda shocked this is not explicitly designed in Atom, or be documented as a practice
#[KevinMarks]hm, checking uk ones and they're using rss and dc
#barnabythat’s why I learned to type them myself, and then turned off auto-curling wherever I could
#barnaby[tantek]: re “uses CDATA for content 🙄”, what’s wrong with that if you’re publishing HTML content which would result in invalid XML if included directly in the ATOM feed? e.g. valid HTML5 void elements like <br> or <img>?
#[tantek]if you can generate valid Atom/XML, you can generate valid XHTML5 for embedding in valid Atom/XML
KartikPrabhu and capjamesg joined the channel
#[snarfed]in some cases yes, but not always easily. eg granary uses CDATA because it sometimes has to to pass through arbitrary input HTML content, and I don’t really want to try to parse that, regenerate it as XHTML5, and handle the 50 resulting cases of lossiness and other bugs that would happen
#barnaby[snarfed]: do you search the 3rd party content for CDATA closing tags? what would happen if some of the arbitrary HTML content included one and prematurely ended the CDATA section?
#barnabyI suppose the only guaranteed-non-fragile method would be to escape all the HTML-relevant characters in the 3rd party content, and then include it in the ATOM without CDATA
#barnabythen it’s just a safe blob of text which is guaranteed to not mess with the surrounding ATOM, and will be parsed to the original content by consumers
#[tantek]escaped HTML? sounds like RSS embedding techniques