On this page:
2.1 Module oauth2/  client.
2.1.1 Authorization
request-authorization-code
authorization-complete
2.1.2 Authorization Token Management
grant-token/  from-authorization-code
grant-token/  implicit
grant-token/  from-owner-credentials
grant-token/  from-client-credentials
grant-token/  extension
oauth-namespace-urn
oauth-grant-type-urn
refresh-token
revoke-token
introspect-token
2.1.3 Resource Access
resource-sendrecv
make-authorization-header
2.1.4 Parameter Creation
create-random-state
2.1.5 Response Error Handling
register-error-transformer
deregister-error-transformer
2.2 Module oauth2/  client/  flow.
initiate-code-flow
2.3 Module oauth2/  client/  pkce.
pkce
create-challenge
verifier-char?
7.8

2 OAuth 2.0 Client

Simple OAuth 2.0 client implementation, with a module based on the specific and individual request/response patterns defined in the specification as well as a higher-level module that implements end-to-end flows.

(require oauth2 oauth2/client)
 
(define response-channel
  (request-authorization-code
   client
   '("scope-a" "scope-b")))
 
(define authorization-code
  (channel-get response-channel))
(displayln (format "received auth-code ~a" authorization-code))
 
(when (exn:fail? authorization-code)
   (raise authorization-code))
 
(define token-response
  (fetch-token/from-code
   client
   authorization-code))
(displayln (format "fetch-token/from-code returned ~a" token-response))

2.1 Module oauth2/client.

 (require oauth2/client) package: simple-oauth2

This module provides request-level procedures that match the sections of the OAuth specification. While each provides a reasonable interface abstraction there remains a 1:1 mapping from the procedures here and the specific HTTP requests described in the corresponding RFCs.

2.1.1 Authorization

procedure

(request-authorization-code client    
  scopes    
  #:state state    
  #:challenge challenge    
  #:audience audience)  channel?
  client : client?
  scopes : (listof string?)
  state : #f
  challenge : #f
  audience : #f
Given a client configuration, and a list of requested scopes, request an authorization code by having the user complete a manual authentication and authorization step via the URI in client-authorization-uri. This is an asynchronous process directing the user to a web page provided by the service to authenticate the request. Upon success the users browser is redirected to a page hosted by this package (the redirect server). To address this, the response from this procedure is a channel which will be to communicate back to the caller the authorization code provided by the service via the redirect server. See The OAuth 2.0 Authorization Framework, §4.1

The value read from the response channel will either be a string? code or an exception (exn:fail:http or exn:fail:oauth2). The authorization code read from the response channel may then be used in a call to grant-token/from-authorization-code to retieve a token for this client.

procedure

(authorization-complete)  void?

The redirect server used in the retrieval of authorization codes utilizes a set of asynchronous resources including blocking threads. These resources are only started when a client calls request-authorization-code for the first time but then they remain in place until the process is terminated or they are shut down explicitly. This procedure performs an orderly shut down of the redirect server.

2.1.2 Authorization Token Management

procedure

(grant-token/from-authorization-code client 
  authorization-code 
  #:challenge challenge) 
  token?
  client : client?
  authorization-code : string?
  challenge : #f
Request the authorization server grant an access token (and usually a refresh token also) given an authorization code previously provided by request-authorization-code.

From The OAuth 2.0 Authorization Framework, §4.1.3: The authorization code grant type is used to obtain both access tokens and refresh tokens and is optimized for confidential clients. Since this is a redirection-based flow, the client must be capable of interacting with the resource owner’s user-agent (typically a web browser) and capable of receiving incoming requests (via redirection) from the authorization server.

procedure

(grant-token/implicit client    
  scopes    
  #:state state    
  #:audience audience)  token?
  client : client?
  scopes : (listof string?)
  state : #f
  audience : #f
From The OAuth 2.0 Authorization Framework, §4.2.1: The implicit grant type is used to obtain access tokens (it does not support the issuance of refresh tokens) and is optimized for public clients known to operate a particular redirection URI. ... Unlike the authorization code grant type, in which the client makes separate requests for authorization and for an access token, the client receives the access token as the result of the authorization request.

procedure

(grant-token/from-owner-credentials client    
  username    
  password)  token?
  client : client?
  username : string?
  password : string?
From The OAuth 2.0 Authorization Framework, §4.3.2: The resource owner password credentials grant type is suitable in cases where the resource owner has a trust relationship with the client, such as the device operating system or a highly privileged application. ... This grant type is suitable for clients capable of obtaining the resource owner’s credentials (username and password, typically using an interactive form). It is also used to migrate existing clients using direct authentication schemes such as HTTP Basic or Digest authentication to OAuth by converting the stored credentials to an access token.

procedure

(grant-token/from-client-credentials client)  token?

  client : client?
From The OAuth 2.0 Authorization Framework, §4.4.2: The client can request an access token using only its client credentials (or other supported means of authentication) when the client is requesting access to the protected resources under its control, or those of another resource owner that have been previously arranged with the authorization server (the method of which is beyond the scope of this specification).

procedure

(grant-token/extension client    
  grant-type-urn    
  [parameters])  token?
  client : client?
  grant-type-urn : string?
  parameters : (hash/c symbol? string?) = (hash)
From The OAuth 2.0 Authorization Framework, §4.5: The client uses an extension grant type by specifying the grant type using an absolute URI (defined by the authorization server) as the value of the "grant_type" parameter of the token endpoint, and by adding any additional parameters necessary.

Note that the grant-type-urn should be a registered IETF value according to An IETF URN Sub-Namespace for OAuth, but the only validation the client performs is that it starts with the prefix value oauth-grant-type-urn.

Example SAML 2.0 extension

(grant-token/extension
 client
 "urn:ietf:params:oauth:grant_type:saml2-bearer"
 (hash 'assertion "PEFzc2VydGlvbiBJc3N1ZUluc3RhbnQ9Ij...IwMTEtMDU"))

These values represent the IETF registered URN prefixes for extension values used to add methods to OAuth. See grant-token/extension.

procedure

(refresh-token client token)  token?

  client : client?
  token : token?
Access tokens are returned to the client along with an expiration duration, thus they periodically become unusable when they expire. If the authorization server also provided a refresh token it may be used to generate a new access token, with a new expiration duration.

From The OAuth 2.0 Authorization Framework, §6: If the authorization server issued a refresh token to the client, the client makes a refresh request to the token endpoint. Note that the token endpoint is the same used for access grants above.

procedure

(revoke-token client token [token-type-hint])  void?

  client : client?
  token : token?
  token-type-hint : string? = #f
From OAuth 2.0 Token Revocation, §2.1: The OAuth 2.0 core specification [RFC6749] defines several ways for a client to obtain refresh and access tokens. This specification supplements the core specification with a mechanism to revoke both types of tokens. A token is a string representing an authorization grant issued by the resource owner to the client. A revocation request will invalidate the actual token and, if applicable, other tokens based on the same authorization grant and the authorization grant itself.

Implementations MUST support the revocation of refresh tokens and SHOULD support the revocation of access tokens

procedure

(introspect-token client    
  token    
  token-type-hint)  jsexpr?
  client : client?
  token : token?
  token-type-hint : symbol?
From OAuth 2.0 Token Introspection, §2.1: This specification defines a protocol that allows authorized protected resources to query the authorization server to determine the set of metadata for a given token that was presented to them by an OAuth 2.0 client. This metadata includes whether or not the token is currently active (or if it has expired or otherwise been revoked), what rights of access the token carries (usually conveyed through OAuth 2.0 scopes), and the authorization context in which the token was granted (including who authorized the token and which client it was issued to). Token introspection allows a protected resource to query this information regardless of whether or not it is carried in the token itself, allowing this method to be used along with or independently of structured token values. Additionally, a protected resource can use the mechanism described in this specification to introspect the token in a particular authorization decision context and ascertain the relevant metadata about the token to make this authorization decision appropriately.

2.1.3 Resource Access

procedure

(resource-sendrecv resource-uri    
  token    
  [#:method method    
  #:headers headers    
  #:data data])  list?
  resource-uri : string?
  token : token?
  method : string? = "GET"
  headers : (listof bytes?) = '()
  data : (or/c bytes? #f) = #f
Make a request to a resource server, protected by token, and return the result. The results are in the form of a four-part list (http-code http-message response-headers response-body).

procedure

(make-authorization-header token)  bytes?

  token : token?
Create a valid HTTP authorization header, as a byte string, from the provided token value. See OAuth 2.0 Token Introspection, §7.1:

2.1.4 Parameter Creation

procedure

(create-random-state [bytes])  string?

  bytes : exact-positive-integer? = 16
Create a random string that can be used as the state parameter in authorization requests. The random bytes are formatted as a byte string and safe for URL encoding.

2.1.5 Response Error Handling

procedure

(register-error-transformer url func)  void?

  url : string?
  func : (-> string? jsexpr? continuation-mark-set? (or/c exn:fail:oauth2 #f))
Specifically for services that do not follow the standard error response format in The OAuth 2.0 Authorization Framework, §4.1.2.1 (or other sections titled Error Response). A client may register an error transformer that will be passed any non-standard JSON error responses from calls to the registered URL, to transform into an exn:fail:oauth2 exception.

(define (fitbit-error-handler uri json-body cm)
  (cond
    [(hash-has-key? json-body 'errors)
     (define json-error (first (hash-ref json-body 'errors '())))
     (make-exn:fail:oauth2 (hash-ref json-error 'errorType 'unknown)
                           (hash-ref json-error 'message "")
                           uri
                           ""
                           cm)]
    [else #f]))
 
(register-error-transformer
 (client-authorization-uri fitbit-client)
 fitbit-error-handler)

procedure

(deregister-error-transformer url)  void?

  url : string?
This procedure removes any error transformer associated with url.

2.2 Module oauth2/client/flow.

 (require oauth2/client/flow) package: simple-oauth2

procedure

(initiate-code-flow client    
  scopes    
  [#:user-name user-name    
  #:state state    
  #:challenge challenge    
  #:audience audience])  token?
  client : client?
  scopes : (listof string?)
  user-name : string? = #f
  state : string? = #f
  challenge : pkce? = #f
  audience : string? = #f
TBD

2.3 Module oauth2/client/pkce.

 (require oauth2/client/pkce) package: simple-oauth2

This module simply provides the constructor for challenge values as specified in RFC7636 - Proof Key for Code Exchange (PKCE) by OAuth Public Clients. PKCE structures may be used in the request-authorization-code and grant-token/from-authorization-code procedures.

struct

(struct pkce (verifier challenge method))

  verifier : bytes?
  challenge : string?
  method : (or/c "plain" "S256")
Values of pkce? are constructed only by create-challenge (there is no make-pkce procedure) and represent the PKCE challenge details.

procedure

(create-challenge [a-verifier])  pkce?

  a-verifier : bytes? = #f
Create a structure that represents the components of a PKCE challenge. The a-verifier value (defined as a high-entropy cryptographic random STRING) can be used as the seed string, if not specified a random byte string is generated.

The following is the specified challenge construction approach from RFC7636, §4.1.

code_challenge = BASE64URL-ENCODE(SHA256(ASCII(code_verifier)))

code-verifier  = 43*128unreserved

unreserved     = ALPHA / DIGIT / "-" / "." / "_" / "~"

ALPHA          = %x41-5A / %x61-7A

DIGIT          = %x30-39

Also, note that while the value "plain" is a valid method according to the PKCE RFC at this time it is not used in this implementation, only the value "S256" will be used.

procedure

(verifier-char? ch)  boolean?

  ch : any?
Implements the unreserved rule from the construction rules above.