Skip to content

Instantly share code, notes, and snippets.

@sebilasse
Last active March 9, 2017 19:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sebilasse/3fa48e758b6828fe30bdee64778d6e4e to your computer and use it in GitHub Desktop.
Save sebilasse/3fa48e758b6828fe30bdee64778d6e4e to your computer and use it in GitHub Desktop.

Proposal : Scoped IndieAuth

draft0 :: extension, completely backwards compatible

Story

As an internet user I would like my personal domain to serve as my online identity and so I am using the best solution, "IndieAuth" :

I have to enter my own domain directly at any page where I want to login , but

  • I can't be sure if the page does implement IndieAuth at all or if the login attempt will be succesful and I would feel better if I could hand out my domain to indieauth.com first.

When I use indieauth.com, the site shows all my rel="me" links and allows to start the authentication process for each supported link.
This is possible for everyone who knows my domain, but

  • for some providers (particularly those directly returning a token, like Mail or SMS) I do not want to let everyone do this.

  • for some providers a reason might exist to not let everyone know the provider's user ID / URL and I do not want them to be visible at all.

Solution (describing the extensions)

step 1

The user visits a site offering IndieAuth and sees a form with the following parameters:

GET type ...
client_id hidden required
redirect_uri hidden required
state hidden required if no me*
me text optional

Example <html> [5]

<form action="https://indieauth.com/auth" method="GET">
  <p><button type="submit">Sign In with IndieAuth</button></p>
  <input type="hidden" name="client_id" value="https://example.com/">
  <input type="hidden" name="redirect_uri" value="https://example.com/auth">
  <input type="hidden" name="state" value="eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJPQXV0aCAyIDNsZWdnZWQiLCJleHAiOjE0ODkwNjcyMDc3MTYsImp0aSI6ImEyNDRhNTMwLThhYjYtNGI0ZS1hMmFmLTQ0OWVjNTI4OTZhMSIsImtpZCI6ImI4NThjYjI4LTI2MTdmYjA5LTU2ZDk2MDIxLTVjOGU4NGQxLWNjZjkwOWM2IiwicmZwIjoie1wibWVcIjpcIi8jMmEwMjpYWFhYOlhYWFg6WFhYWDQwOjYwODA6WFhYWGNjOmZiMzU6WFhYWCwyYTAyOlhYWFg6WFhYWDpYWFhYNDA6NjA4MDpYWFhYY2M6ZmIzNTpYWFhYXCIsXCJpZFwiOlwidXladnlROUNaZEpBcklhY2lnVEtTY3pyQWNqamoyU1BNdzRJMnJrT1FcIn0iLCJhcyI6Imh0dHBzOi8vcmVkYWt0b3IuY2lyY2ludXMudWJlcnNwYWNlLmRlL3JlZGFrdG9ybm9kZS9jYWxsYmFjayJ9.8SCyD_HGLtuMXNvDqs1CLR7txiGF1T7yh1EuP2pFrSM">
</form>

*) state is a random value to start the authentication process for example see draft-bradley
The client_id should check after a successful auth if the state matches the one in the session or a hash in a cookie ...

step 2

User clicks the button, IndieAuth can do the rest:
When the submitted form contains no me, additionally

  • IndieAuth checks if the state parameter is given and stores it in an initial session together with a secret to sign the RFP token used as described in draft-bradley
  • IndieAuth presents
<form action="https://indieauth.com/auth" method="POST">
  <label for="indie_auth_url">Your Web Address:</label>
  <input id="indie_auth_url" type="text" name="me" placeholder="yourdomain.com" />

  <p><button type="submit">Sign In with IndieAuth</button></p>

  <input type="hidden" name="client_id" value="GIVEN">
  <input type="hidden" name="redirect_uri" value="GIVEN">
  <input type="hidden" name="csrf" value="GIVEN">
</form>

[ note: The me field should be prefilled with the session value (where the AuthToken is expired) or otherwise leave autofill to the browser settings, the form should be CSRF protected. ]

The user enters the domain in the me field and IndieAuth adds it to the session ...

step 3

After IndieAuth has checked all of the me's rel="me" links :
If the rel="me" link is "PUBLIC" anything is as it is now,
else ::

A) Initial Scopes

the rel="me" links

type visible reachable start auth
PUBLIC yes yes yes
PROTECTED base64decode yes, proxy enter password
PRIVATE no no enter password

Examples <html> [5]

PUBLIC
<a href="mailto:me@example.com" rel="me">me@example.com</a>
[there could be a SPAM warning for mail/sms]

PROTECTED
<a href="https://indieauth.com/redirect?redirect_uri=JWS" rel="me">mail me</a>

redirect_uri is a JWS (signed JWT) with the following claims:
[all claims except "priv" are JWT conventions]

{
  iss: 'example.com', // chosen by user
  as: "mailto:me@example.com",
  exp: 0,
  jti: 'uuid()', // token uuid4
  kid: 'uuid()', // key unique id
  priv: false
}

The different providers could then specify additional claims, e.g. mail could allow html sending, a joke and DKIM or GPG signing

{
  html: true,
  xkcd: false,
  dkim: false
}

When such a protected link is clicked, IndieAuth will redirect after base64decode and when such a link is recognized for auth the signature password must be entered first by the user to check the signature.

PRIVATE
as in PROTECTED but the as claim must be AES encrypted with the signature password and the priv claim must be true ...

Such a private link must appear as link in <head> and can't be clicked and when such a link is recognized for auth the signature password must be entered first by the user to check the signature and decrypt as.

References

https://www.ietf.org/id/draft-bradley-oauth-jwt-encoded-state-06.pdf

Contributing

  1. Fork it!
  2. Discuss!

< . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . >

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment