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
client - the client configuration for the service performing the authorization.
scopes - a set of scopes to which we are requesting access.
state - (optional) a state value, returned to the redirect server for request/response correlation.
challenge - (optional) a PKCE challenge structure, if #f PKCE will not be used. See Proof Key for Code Exchange (PKCE) by OAuth Public Clients, §4.3.
audience - (optional) a non-standard value used by some services to denote the API set to which access is requested. if #f this parameter will not be sent.
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
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
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.
client - the client configuration for the service granting the token(s).
authorization-code - a valid authorization code.
challenge - (optional) a PKCE challenge structure, if #f PKCE will not be used. See Proof Key for Code Exchange (PKCE) by OAuth Public Clients, §4.5.
procedure
(grant-token/implicit client scopes #:state state #:audience audience) → token? client : client? scopes : (listof string?) state : #f audience : #f
client - the client configuration for the service performing the authorization.
scopes - a set of scopes to which we are requesting access.
state - (optional) a state value, returned to the redirect server for request/response correlation.
audience - (optional) a non-standard value used by some services to denote the API set to which access is requested. if #f this parameter will not be sent.
procedure
(grant-token/from-owner-credentials client username password) → token? client : client? username : string? password : string?
client - the client configuration for the service performing the authorization.
username - the name of the resource owner being authorized.
password - the password for the resource owner being authorized.
procedure
(grant-token/from-client-credentials client) → token?
client : client?
client - the client configuration for the service performing the authorization.
procedure
(grant-token/extension client grant-type-urn [ parameters]) → token? client : client? grant-type-urn : string? parameters : (hash/c symbol? string?) = (hash)
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.
client - the client configuration for the service performing the authorization.
grant-type-urn - the absolute URI (actually verifies it as a URN) that identifies the grant_type extension.
parameters - (optional) a mapping of symbols that represent grant parameter names and string values.
Example SAML 2.0 extension
(grant-token/extension client "urn:ietf:params:oauth:grant_type:saml2-bearer" (hash 'assertion "PEFzc2VydGlvbiBJc3N1ZUluc3RhbnQ9Ij...IwMTEtMDU"))
value
value
procedure
(refresh-token client token) → token?
client : client? token : token?
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.
client - the client configuration for the service performing the authorization.
token - the token structure, the token-refresh-token value will be used to generate a new token-access-token value.
procedure
(revoke-token client token [token-type-hint]) → void?
client : client? token : token? token-type-hint : string? = #f
Implementations MUST support the revocation of refresh tokens and SHOULD support the revocation of access tokens
client - the client configuration for the service performing the authorization.
token - the token to revoke.
token-type-hint - (optional) determines the type of token to send to the server. One of 'access-token or 'refresh-token.
procedure
(introspect-token client token token-type-hint) → jsexpr? client : client? token : token? token-type-hint : symbol?
client - the client configuration for the service performing the authorization.
token - the token to introspect.
token-type-hint - (optional) determines the type of token to send to the server. One of 'access-token or 'refresh-token.
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
procedure
(make-authorization-header token) → bytes?
token : token?
2.1.4 Parameter Creation
procedure
(create-random-state [bytes]) → string?
bytes : exact-positive-integer? = 16
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))
(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?
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
client - the client configuration for the service performing the authorization.
scopes - a set of scopes to which we are requesting access.
state - (optional) a state value, returned to the redirect server for request/response correlation.
user-name - (optional) the user name to record the token under; if #f then the value of get-current-user-name will be used.
challenge - (optional) a PKCE challenge structure, if #f PKCE will not be used.
audience - (optional) a non-standard value used by some services to denote the API set to which access is requested. if #f this parameter will not be sent.
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")
procedure
a-verifier : bytes? = #f
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?