[Openid-specs-ab] Native SSO spec feedback

George Fletcher gffletch at aol.com
Wed Jul 3 18:44:05 UTC 2019

Sigh... I'm just getting to updating the spec. I'll share updated XML 
and HTML later today.

Comments inline...

On 2/28/19 11:44 AM, Filip Skokan wrote:
> You're welcome George, please find my feedback inline.
> Best,
> *Filip*
> On Thu, 28 Feb 2019 at 16:56, George Fletcher <gffletch at aol.com 
> <mailto:gffletch at aol.com>> wrote:
>     First, thank you very much for your feedback and I sincerely
>     apologize for not getting back to you sooner!
>     Comments inline.
>     On 1/18/19 5:46 AM, Filip Skokan wrote:
>>     Hello George,
>>     I've re-read the document and updated my past feedback draft.
>>     Here goes
>>     *Section 3.2 *
>>         > and as such it is RECOMMENDED that the device secret be
>>         implemented as a JWE encrypted for the
>>         > Authorization Server.
>>     This recommendation suggests that the AS does not store the
>>     device secret state, why is JWE?? recommended over any opaque
>>     value representing the device secret state stored on AS side?
>     We can relax this to allow for a client only vs server state
>     solution. As to JWE, I often recommend it because it makes it easy
>     to do key rotation and good security hygiene says keys should be
>     rotated. That say, I agree that we don't have to be prescriptive
>     around how in that the value is opaque to the client.
> FS: ????
>>         > The client MAY provide the "device_secret" to the /token
>>         endpoint during refresh token requests.
>>     Why? What's the AS supposed to do, refresh the device secret too?
>>     Validate it as well? Should the AS rotate the secret, is the
>>     client expected to update the shared storage with every new
>>     device secret it receives? Given the previous recommendation to
>>     use a JWE, how to handle rotation or revocation, if it's just an
>>     opaque value leading to a record on the side, should the used
>>     ones be marked as consumed and when re-used revoke the grant as a
>>     whole?
>     So we have the requirement that the server should be able to
>     update the device secret if needed. This provides a way for the
>     device secret to be "rotated". As to issuing of access_tokens in
>     the refresh_token grant flow, then I'd suggest that the
>     device_secret represent the device to which the refresh_token was
>     issued. This creates a tighter binding between the refresh_token
>     and the device.
>     Yes, if an "old" device_secret is used, I would reject the entire
>     /token grant_type flow.
>     Note that support for other grant_types other than refresh_token
>     may require device_secret validation.
>     Also, my expectation is that device_secrets contain a unique id
>     (like a jti) that can be used on the server side for management,
>     blacklisting, etc.
> FS: If the intention is for the server to rotate it using its policies 
> it should be required to be present. e.g. if a refresh token is 
> received at the token endpoint which has the "device_sso" scope the 
> device_secret is a required parameter? Too strict? Dunno, but this way 
> it looks like it's up to the client to control the rotation by 
> including it or not. That way, as an implementer i'm forced to load 
> the device_secret by either reference or other means (decode/decrypt) 
> and i can easily confirm the refresh token and device secret belong to 
> one another and that the device secret is not expired / revoked or 
> similar.
I'm updating the spec to say SHOULD instead of MAY. If there is general 
agreement, I don't mind making it a MUST in the case of a refresh_token 
that "contains" a device_sso scope.
>>     *Section 3.3*
>>     Why would an app already in possession of a device_secret go
>>     through browser based code flow when it can do token exchange? If
>>     that one was rejected, then a browser based code flow? And the
>>     point of providing the previously rejected device_secret is?
>     It's required so that the id_token can be issued with the
>     device_secret hash (ds_hash). This allows the id_token,
>     access_token and refresh_token to be bound to the device_secret.
>     This constrains these tokens to that device.
> FS: I'm not sure I follow. I know ID Token being returned from refresh 
> token grant or token exchange in this case is optional, but still, as 
> a client if I get a device secret from the shared storage my instinct 
> reaction is to do the token exchange, not to start a regular flow. It 
> just looks to me like this is out there without an explanation on WHY 
> a client would ever do a regular auth flow when it's already in 
> possession of a device secret.
GFF: So if a device_secret and id_token exist when the native app loads, 
it doesn't need to do the initial browser based flow. The only time the 
browser based flow is required is if the device_secret and associated 
id_token are NOT present on the device or the user want to login with a 
different identity.
>>     *Section 3.4*
>>         > ds_hash
>>         > The exact binding between the ds_hash and device_secret is
>>         not specified by this profile. As this
>>         > binding is managed solely by the Authorization Server, the
>>         AS can choose how to protect the
>>         > relationship between the id_token and device_secret.
>>     Why not use the same boilerplate used for other *_hash ID Token
>>     properties?
>     We can. Partly because if the device_secret contains a randomly
>     generated unique id (e.g. jti) then it might not really be
>     required to hash the whole device secret. I should probably update
>     the spec with this and am also interested in your thoughts.
> FS: The device_secret being either opaque or JWT it's always unique, 
> else it doesn't serve it's purpose right. Ergo, i'd say the ds_hash is 
> calculated the same way other hash properties are.
I think one problem here is that if the device_secret is updated, it 
will have a different hash value and now the ds_hash in the id_token 
won't validate against the device_secret. I want to keep the binding but 
not require issuing new id_tokens when the device_secret changes. In 
this context, maybe hash is the wrong working and we should change the 
claim name to 'ds_id' or something like that.
>>     e.g.
>>         > OPTIONAL. Device Secret hash value. Its value is the
>>         base64url encoding of the left-most half of
>>         > the hash of the octets of the ASCII representation of the
>>         device_secret value, where the hash
>>         > algorithm used is the hash algorithm used in the alg Header
>>         Parameter of the ID Token's JOSE
>>         > Header. For instance, if the alg is RS256, hash the
>>         device_secret value with SHA-256, then take
>>         > the left-most 128 bits and base64url encode them. The
>>         ds_hash value is a case sensitive string.
>>     *Section 4.1*
>>         > The client MUST use the HTTP Basic Authentication method
>>         from RFC
>>         > 6749 to authenticate the request to the token endpoint.
>>     1) client_secret_basic without client_secret makes little sense
>>     and in general an AS will issue a client secret when client's
>>     token_endpoint_auth_method is client secret based.
>     So what is the preferred way for a PKCE client to present it's
>     client_id? Given the current token exchange spec, I believe the
>     only way is in the HTTP Authorization header. Happy for
>     suggestions here.
> FS: OIDC Core Section 9 gives a name to such auth method, it's "none" 
> and the client_id is provided in the body of the request and the Token 
> Exchange spec also mentions "Client authentication to the 
> authorization server is done using the normal mechanisms provided by 
> OAuth 2.0.". Again this goes to the next point, i'd just stick to the 
> boilerplate and not force a client to use a specific authentication 
> scheme.
>>     2) I wouldn't specify the required authentication method at the
>>     token endpoint, i'd say something along the lines of "the client
>>     authenticates using its registered token endpoint authentication
>>     method". Albeit this is most likely going to be "none" but we
>>     shouldn't rule out dynamically registered clients with secrets or
>>     private_key_jwt auth.
>     This is a good point as I'd like to look at how this works with
>     dynamic client registrations using private_key_jwt. I'll see about
>     updating the text accordingly.
> FS: ????
>>     Furthermore any AS implementation probably has the "client
>>     authentication" abstracted before any specific grant type
>>     processing and it would be a hassle to add extra auth processing
>>     based on the grant type.
>     Fair point.
>>     *dtto in 4.2*, the example should be a non-normative example
GFF: I consider all examples non-normative. Should I explicitly state that?
>>     *Section 4.3*
>>         > If that session expires, all refresh_tokens associated with
>>         it MUST be invalidated.
>>     Regardless of present offline_access scope and consent on the
>>     initial authorization request?
>     Good point. I need to address the 'offline_access' scope scenario.
>     I believe that even in an offline_access scenario, the server can
>     invalidate the refresh_token so the concept needs to stay.
>     Effectively, there needs to be a way for the id_token to reference
>     something for the long-lived "session" such that if that session
>     is revoked, the token exchange failed.
>     session_id could possibly be replaced with refresh_token_id for
>     the offline_access case. Thoughts?
> FS: I probably skimmed though 4.3 the first time, because point of it 
> 2 says the token endpoint should verify binding between an id token 
> and a device secret. Where did id_token come from? The client doesn't 
> send one, just sends the refresh token and possibly? the device secret.
GFF: the id_token is specified in the 'subject_token' parameter of the 
token exchange profile
>>     *Section 4.4*
>>       * expires_in should be RECOMMENDED or OPTIONAL to be in line
>>         with the rest of the specifications
>>       * refresh_token REQUIRED? The point is to obtain an ID and
>>         Access tokens, i'd expect issuing a refresh token is left to
>>         the AS policy discretion
>     Yes, we should leave it up to the AS. What I'd like to describe is
>     that if the new client SHOULD receive a refresh_token for it's own
>     flows, then the AS needs to provide one because the refresh_token
>     is issued to the new client_id. That said, there could be some
>     flows (though unlikely in a mobile environment) where the AS does
>     NOT issue refresh_tokens so it shouldn't be REQUIRED.
>>     Example response has a few nits
>>       * has "Issued_token_type" property name (capital I)
>>       * should be marked as non-normative
>>       * token_type although case-insensitive value should be "Bearer"
>>         to be inline with the rest of the specs
>     Thanks!
>>     *Section 6.1. *
>>     `sid` would already be registered by both front and back-channel
>>     specs, wouldn't it?
>>     *6.2.1. is probably a leftover copy-paste*
>     *Thank you!! This is very helpful!*
>>     Best,
>>     Filip

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.openid.net/pipermail/openid-specs-ab/attachments/20190703/3ddb2dfd/attachment-0001.html>

More information about the Openid-specs-ab mailing list