OAuth token spec

107 views
Skip to first unread message

Alex Bilbie

unread,
Aug 21, 2015, 11:33:18 AM8/21/15
to thephpleague
So Frank sent this tweet out earlier - https://twitter.com/frankdejonge/status/634727793805406209

A number of people joined Frank in discussing this proposal and to sum up roughly where the conversation led to what is being proposed is a value object class that describes an access token that can be used by PHP packages that have to consume or produce access tokens.

I created a very quick first attempt here: https://gist.github.com/alexbilbie/833024da674ecc7e5e61

Frank originally proposed that it becomes a PSR; I'm inclined to disagree as I'm sure we'd all much rather have something sooner than it would otherwise take to get a proposal through the FIG.
I personally think an OAuth namespace should be minted and as the League has some of the most popular OAuth-related packages available we [the League] sponsor/host the repository. Having said that if the consensus is going down the FIG-route I'd be more than happy to get involved.

Some other thoughts/ideas I have:

* The classes needs to be kept as simple and generic as possible as identity provider implements OAuth differently
* After instantiation the object should be immutable (i.e. no setter methods aside from the constructor)
* It might be interesting to subclass the main AccessToken class with provider specific classes - for example "FacebookAccessToken" and we have some sort of interface to go along with it that has a method called `refresh()` with which you could pass the FacebookAccessToken instance into the interface implementation and it can handle refreshing the access token and returning a new instance...
* We do need to reach out to other popular OAuth-releated PHP packages to get them involved for this to take off

So, lets see where this goes...

Alex

Dustin Wheeler

unread,
Aug 21, 2015, 11:37:37 AM8/21/15
to thephpleague
Thanks Alex,

Pasting this from my comment on Gist and deleting that comment.

Access Token (http://tools.ietf.org/html/rfc6749#section-1.4)

Access tokens are credentials used to access protected resources. An
access token is a string representing an authorization issued to the
client. The string is usually opaque to the client. Tokens
represent specific scopes and durations of access, granted by the
resource owner, and enforced by the resource server and authorization
server.

Resource Owner (http://tools.ietf.org/html/rfc6749#section-1.1)

An entity capable of granting access to a protected resource.
When the resource owner is a person, it is referred to as an
end-user.

The highlights above are important (to me, at least) no matter service provider specific implementations. If the discussion is scoped to standardizing ONLY the access token, then service provider implementation specifics can be accommodated by appropriate interfaces. Personally, I feel like a lot of the API decisions for clients/server implementation assume a unified authorization / resource server and this leads to cloudiness in responsibility but if I get an access token handed to me, I should be able to determine (from whatever concretion) those highlighted concepts.

I like the AccessToken above with a few adjustments:

  • Resource owner should be an abstraction that allows vendors to control implementation of "resource owner identity". The end result may very well be a string, but wrapping it reifies the abstraction beyond some arbitrary text. The key here though is that we're talking about an entity that is uniquely addressable. We can take the spec a step-further by standardizing what that means. An example would serve well here (I'll bake something).
  • Scope of access should be included. Foresight to accommodate facilities easy checking of scopes would be gravy. Accommodating comparison of access scope would also be useful, but is likely overstepping bounds of responsibility. This has primary application in implementation of refresh tokens on authorization servers where by you may refresh at the same or lower scope of access.
  • Type is going to be an interesting one to discuss. I assume it's here only as a marker for implementation (e.g. Authorization: {:type} {:value})

/edit I included the reference material above to help guide my own writing more than anything, not as a presumption that folks are unaware. My perceived tone when writing is a problem and wanted to make sure I wasn't coming across as offensive.

Ben Ramsey

unread,
Aug 21, 2015, 11:40:36 AM8/21/15
to Alex Bilbie, thephpleague
Thanks for getting this thread started, Alex.

On Aug 21, 2015, at 10:33 AM, Alex Bilbie <he...@alexbilbie.com> wrote:

So Frank sent this tweet out earlier - https://twitter.com/frankdejonge/status/634727793805406209

A number of people joined Frank in discussing this proposal and to sum up roughly where the conversation led to what is being proposed is a value object class that describes an access token that can be used by PHP packages that have to consume or produce access tokens.

I created a very quick first attempt here: https://gist.github.com/alexbilbie/833024da674ecc7e5e61

Frank originally proposed that it becomes a PSR; I'm inclined to disagree as I'm sure we'd all much rather have something sooner than it would otherwise take to get a proposal through the FIG.

This sounds good, and I’m not entirely convinced of the value of such a PSR. Do we have a lot of interop issues in the community surrounding varying uses of OAuth tokens?

I personally think an OAuth namespace should be minted and as the League has some of the most popular OAuth-related packages available we [the League] sponsor/host the repository. Having said that if the consensus is going down the FIG-route I'd be more than happy to get involved.

Some other thoughts/ideas I have:

* The classes needs to be kept as simple and generic as possible as identity provider implements OAuth differently

I think they should be interfaces to be implemented by various packages (oauth2-client, oauth1-client, and their dependent packages), rather than a set of classes to be used.

* After instantiation the object should be immutable (i.e. no setter methods aside from the constructor)

Agreed.

* It might be interesting to subclass the main AccessToken class with provider specific classes - for example "FacebookAccessToken" and we have some sort of interface to go along with it that has a method called `refresh()` with which you could pass the FacebookAccessToken instance into the interface implementation and it can handle refreshing the access token and returning a new instance…

This doesn’t make sense to me. I think each OAuth client provider package might subclass and implement the token themselves, but I don’t think we need a repository filled with service provider token classes. With oauth2-client, we made the decision to split all that up for easier maintenance and better abstraction, and I think we should strive for that here, too.

Frank de Jonge

unread,
Aug 21, 2015, 11:41:05 AM8/21/15
to thephpleague
I'd say the two routes could even co-exist. An extracted token abstraction backed by an interface declaration (a PSR) would make a very powerful combination. If there would have to be a choice to be made, I'd be leaning more to the PSR route. Reasons for this is mainly to remove the vendor from the equation. Even if the interface is so simple that there's only one sensible implementation, not demanding people to depend on a concrete implementation is a win in my book. Not only will this boost adoption because the NIH-symdrone is less likely to kick in, it also allows people to expand on the interface for internal use without being forced to extend from the given implementation.

- Frank

Op vrijdag 21 augustus 2015 17:33:18 UTC+2 schreef Alex Bilbie:

Woody Gilk

unread,
Aug 21, 2015, 11:41:54 AM8/21/15
to Dustin Wheeler, thephpleague
I'll repeat the comment I made on the Gist:

A couple of suggestions for additions:

- implement the JsonSerializable interface
- add a toArray (or similar) method to return all of the values as an array for easy persistence

Overall I really like this suggestion and I think it makes a lot of sense. I'm not entirely certain that having "DateTime expiresAt" is more useful than a UNIX timestamp, because DateTime comes with timezone baggage that may cause hard to identify errors.

--
You received this message because you are subscribed to the Google Groups "thephpleague" group.
To unsubscribe from this group and stop receiving emails from it, send an email to thephpleague...@googlegroups.com.
To post to this group, send email to thephp...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/thephpleague/7479b936-959f-48b8-9f39-89c68675e3b8%40googlegroups.com.

For more options, visit https://groups.google.com/d/optout.

Ben Ramsey

unread,
Aug 21, 2015, 11:49:43 AM8/21/15
to Woody Gilk, Dustin Wheeler, thephpleague
> A couple of suggestions for additions:
>
> - implement the JsonSerializable interface
> - add a toArray (or similar) method to return all of the values as an array for easy persistence
>
> Overall I really like this suggestion and I think it makes a lot of sense. I'm not entirely certain that having "DateTime expiresAt" is more useful than a UNIX timestamp, because DateTime comes with timezone baggage that may cause hard to identify errors.

I agree with Woody on all these points. Here are a few more nitpicks on the Gist:

As I said earlier, I’d prefer to see interfaces, rather than an implementation.

I’m not sure what the $ownerType is. It’s “user” in this default implementation, but what other values could it have, and where does this information come from? It’s not in the OAuth standard, and I’ve not seen many cases where the access token response contains enough information to provide this. Can you give a use-case for illustration purposes?

The $ownerId parameter is also tricky. Not all OAuth service providers return an owner ID in the response, and if they do, there’s no standard for what it should be named. That can be left to the implementor to grab the correct value to pass into the constructor, but if there’s no value, then there will be problems with the current interface.

-Ben

Alex Bilbie

unread,
Aug 21, 2015, 11:53:27 AM8/21/15
to thephp...@googlegroups.com
OAuth is also used for machine-to-machine authorization (through grants such as resource owner password grant).

Therefore an access token may represent authorization granted to a machine instead of a user.

Let's not get too hung up on the gist; it was created for the purpose of the Twitter conversation.

Alex Bilbie

unread,
Aug 21, 2015, 11:59:54 AM8/21/15
to thephp...@googlegroups.com
So the properties we need to consider are:

* The authorisation which is represented as a string
* An expiration time (the authorisation server presents a TTL in seconds for the access token)
* An optional list of scopes (returned from the server in the form of  space-seperated list)
* An optional refresh token which is also a string, used to refresh the access token which results in a new instance
* Optional arbitrary key/pair values which the authorisation server may additionally include in its response to the client

In addition we may also want to consider:

* The owner of an access token (which may or may not - generally not) be transparent to the client when an instance is instantiated (for example Facebook gives you an access token and you call `GET /me` to discover the user)

Woody Gilk

unread,
Aug 21, 2015, 12:03:16 PM8/21/15
to Alex Bilbie, thephp...@googlegroups.com
On Fri, Aug 21, 2015 at 10:59 AM, Alex Bilbie <he...@alexbilbie.com> wrote:
* An optional list of scopes (returned from the server in the form of  space-seperated list)

I've never seen this come back in a token response. Does it exist as an option in the OAuth spec?

Dustin Wheeler

unread,
Aug 21, 2015, 1:56:51 PM8/21/15
to thephpleague, he...@alexbilbie.com
I've never seen this come back in a token response. Does it exist as an option in the OAuth spec?

Yep! See "scope" defined in token response: https://tools.ietf.org/html/rfc6749#section-5.1

In addition, a resource server can request information about a given token according to OAuth Token Introspection (https://tools.ietf.org/html/draft-richer-oauth-introspection-06), which includes basically the same information. The need for this gets left out because so many implementations conflate responsibility of AS and RS with an assumption they are deployed as one and the same. For most service providers, this may be the case (Google, Facebook, etc.) because they are both the authoritative account store for resource owners AND the warehouse of protected resources.

However, at least in my case, I am responsible for maintaining an authorization server whereby I have no control over the resource servers that crop up. I simply provide a centralized resource registrar and authorization services to those resources and clients alike.

Matt Frost

unread,
Aug 21, 2015, 3:28:46 PM8/21/15
to thephpleague, he...@alexbilbie.com
I hadn't considered the scope either, I know it comes back with the Access Token response. I was looking at it through a different lense, I was looking at the Access Token and the Refresh Token as different entities. I could see making the expiration a property on the token, but I was coming at it from a perspective of "what would be needed from a Token in order for it to be used with a client". I look at the scope and expiration as useful information, but not necessary in the scope of using the token. That seems like something to me that would be persisted somewhere when the token is actually received. I'm not braining super well today, so it's possible I'm missing something obvious; just trying to think about it from a contractual standpoint trying to consider OAuth 1 and 2. If the goal is to come up with an interface to handle all the Token Types, I think it's as simple as:
Interface Token { public function getValue()} - though value isn't the right word.

I could see adding interfaces for AccessToken, RefreshToken, Temporary Token to handle some of the differences and provide some flexibility; I'm sure there is a use case for having the scope and expiration as attributes of a Token, I just don't can't think of one.

I'm a little late to the party here, so if this doesn't make sense feel free I can clarify when I get home. This is more of a stream of consciousness than an actual idea.

Ben Ramsey

unread,
Aug 21, 2015, 3:41:17 PM8/21/15
to Matt Frost, thephpleague, he...@alexbilbie.com

On Aug 21, 2015, at 2:28 PM, Matt Frost <mfrost...@gmail.com> wrote:

I could see adding interfaces for AccessToken, RefreshToken, Temporary Token to handle some of the differences and provide some flexibility; I'm sure there is a use case for having the scope and expiration as attributes of a Token, I just don't can't think of one.

I tend to think of the refresh token as a property of the access token, so I don’t see a need to model it as a separate entity. Not all authorization servers provide refresh tokens.

I think modeling other token types (temporary token, etc.) is out of scope, but it boils down to the use case for why we want to come up with a standard interface, which I think is this:

Given any client/application/framework that uses OAuth access tokens, one should be able to construct an access token object that conforms to a standard interface and pass it into that client/application/library/framework.

So, in the case of oauth2-client, our provider getAccessToken() method would return an object that conforms to this interface, so any other client/application/library/framework that knows this interface can use it.

What I don’t quite understand beyond this is what other applications/frameworks have need to use an access token generated by oauth2-client (or any other client). What is the interop need?

I’m not trying to play devil’s advocate here; I’m looking for a real-world use-case, so that I can grok the problem we’re trying to solve.

Cheers,
Ben

Alex Bilbie

unread,
Aug 21, 2015, 3:42:20 PM8/21/15
to Matt Frost, thephpleague
I agree Matt, we need a high level generic token interface which only deals with the token's value and can be used as the base for OAuth 1 and 2 access tokens, as well as auth codes and other temporary tokens which add additional meta as it's available.

Whilst few providers inform the client of the final scopes for that do it is useful information to the client. For example if a user denies access to their email address but ultimately approves access to the client it means the client can make an intelligent decision as to which API calls to make and data it can expect in response.

If we go down the PSR route for defining interfaces what is their preferred approach? Do we fork their standards repository and then summit a PR later on with our proposal and sponsors?

Woody Gilk

unread,
Jan 31, 2016, 11:10:53 AM1/31/16
to Alex Bilbie, Matt Frost, thephpleague
I'm reviving this ancient thread... did anyone ever make progress on this? Does anyone have thoughts on what the best way to approach it would be? Should we try to muster it through FIG, or just creating a League package?

Does the token need to include an implementation, or just an interface? Should the implementation be immutable?
--
You received this message because you are subscribed to the Google Groups "thephpleague" group.
To unsubscribe from this group and stop receiving emails from it, send an email to thephpleague...@googlegroups.com.
To post to this group, send email to thephp...@googlegroups.com.

Ben Ramsey

unread,
Feb 13, 2016, 6:19:33 PM2/13/16
to Woody Gilk, Alex Bilbie, Matt Frost, thephpleague
I think it's a good idea.

For starters, it should be an interface. It would be nice if implementations are immutable, but there's no way to enforce that through an interface in PHP.

I think we take what Alex started (https://gist.github.com/alexbilbie/833024da674ecc7e5e61) and the approach we took in oauth2-client (https://github.com/thephpleague/oauth2-client/blob/d94b2a9076622a015ed12dc727b0b34150e659a3/src/Token/AccessToken.php) and use these as starting points.

The League could potentially have a single implementation package (i.e. league/oauth-token or league/access-token) that both oauth1-client and oauth2-client end up using.

I know Woody will be at Midwest PHP. Will anyone else who is interested in this discussion be there? Maybe we can get together to hash out a few ideas.

-Ben



Woody Gilk

unread,
Mar 4, 2016, 9:41:41 PM3/4/16
to thephpleague, Ben Ramsey
As per a discussion that Ben and I had tonight, we'll be proceeding with making a league/oauth-token package. I will come up with a proof of concept interface soon and post it for review. Ideally the interface would be used in both oauth1-client and oauth2-client. The only compatibility issues I see with the existing specs is that the oauth1-client token includes the "token type" which is generally vendor specific, and that the oauth2-client token includes a refresh value which is not applicable to oauth1-client but could simply be left blank.

Woody Gilk

unread,
Mar 5, 2016, 10:36:52 AM3/5/16
to thephpleague, b...@benramsey.com
Here is my first PR, this deals with the lowest level of the shared token interface: https://github.com/shadowhand/oauth-token/pull/1

If this looks good, I would request that the package be moved into league and we start moving towards OAuth1Token and OAuth2Token interfaces. I've looked at the specs and these two specs have quite different values:

OAuth1Token (token, token_secret)
OAuth2Token (access_token, token_type, expires_in, refresh_token, scope)

As per the PoC that Alex wrote up, I think that the "expires_in" parameter should be exposed as "expires_at" to avoid ambiguity about timestamp vs number-of-seconds.

Let me know what you all think!

Regards,
-Woody
To unsubscribe from this group and stop receiving emails from it, send an email to thephpleague+unsubscribe@googlegroups.com.

To post to this group, send email to thephp...@googlegroups.com.

--
You received this message because you are subscribed to the Google Groups "thephpleague" group.
To unsubscribe from this group and stop receiving emails from it, send an email to thephpleague+unsubscribe@googlegroups.com.

To post to this group, send email to thephp...@googlegroups.com.
Reply all
Reply to author
Forward
0 new messages