Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

Resolving the issues stated above simply make the authentication process more secureprovides additional flexibility, and provides users with additional protections, with the trade-off being increased susceptibility to replay attacks (which should be prevented by https).

This sample scenario identified by Jordan Kiang (Unlicensed) is useful as it helps determine additional requirements:

...

  • A user must be able to issue multiple refresh access tokens

  • A user must be able to view metadata about their active tokens, e.g. scope, a custom name/identifier

  • A user must be able to revoke an individual access token

  • Generated access tokens must use scopes as defined in the OAuth 2 implementation

  • Generated access tokens should only expire if unused for 180 days or manually revokedFrom the perspective of

  • a client application, access tokens must be “stateless”, i.e. they are not single use or rotatingA client application should be able to access a token from a read-only key store and multiple, parallel client processes should be able to use the token without being concerned about concurrency issues.

  • Generated access tokens should be bearer tokens

    • A password/session token must not be required to use an access token

    • Functionality identical to OAuth access tokens is preferred

  • It should be impossible for any actor to determine the token other than the issuer at creation time (i.e. store a hash).

...

Service

Request Parameters

Response Body

Notes

POST /auth/v1/userGeneratedTokenpersonalAccessToken

Body:

AccessTokenGenerationRequest {

name: string (a unique-to-the-user, human-readable name. if unspecified, a UUID will be generated)

scope: Array<OAuthScope> (scopes granted by the token)

claims: OIDCClaimsRequest (claims granted by the token)

}

AccessTokenGenerationResponse {

token: String, An opaque, cryptographically-unguessable string (A signed JWT access token.

metadata: AccessTokenRecord, metadata related to the token. See below for fields.

)

}

Generates a token that users can copy and paste into the command line client.

GET /auth/v1/userGeneratedToken personalAccessToken

None

Paginated list of AccessTokenRecord: {

id: unique ID of the access token

scope: Array<OAuthScope> scope of the token

claims: claims granted by the token

name: string, human readable name

lastUsed: the last time an access token was used

createdOn: the date/time the access token was created

state: enum (ACTIVE or EXPIRED)

}

Retrieves a paginated list of the user’s generated access tokens. Tokens that are active or expired will appear. Tokens that have been revoked (deleted) will not appear.

DELETE /auth/v1/personalAccessToken/userGeneratedToken Param (only one is required){id}

Path param:

id: the id of the token to delete

OR

token: the token to delete

None

Revokes the token if it’s a valid access token.

How to use a personal access token

The personal access token can be used by doing two things

...

Put a valid identifier, (e.g. username) in the userId header (just like API keys)

...

putting the token in the Authorization header with the ‘Bearer’ keyword preceding the token (Authorization: Bearer <token>)

Open Questions

Which of these services be accessible via scoped access tokens?

  • I think by default, creating/deleting should not be accessible at all. If a use case comes up, then these can be accessible via the authorize scope. Viewing the list of tokens can be done with the view scope.

What should the token look like? Some options

  • Non-expiring, signed JWT (containing an integer token ID and a user ID)

  • Opaque token

    • With or without additional userId header?

This is partially an implementation question. The ability to revoke tokens requires storing tokens or token identifiers in persistent storage. Performance is critical because a database lookup will be done for every authenticated request made using one of these tokens.