Next: , Previous: , Up: Top   [Contents][Index]


14 Running a client

The job of the client is to use accounts to fetch private resources on the web. The (webid-oidc client) defines the <client> class.

Class: <client> client-id key-pair redirect-uri

In OIDC, a client is an application that does not hold the resources. It may in fact be a network server available on the web, or a program that you run on your machine. Being a network server or not is irrelevant.

The <client> class is designed with immutability in mind. You can create a client with the make generic method, using these keywords to initialize values:

#:client-id

to set the public client identifier (this endpoint should be available on the world-wide web), as a string representing an URI or an URI from (web uri);

#:key-pair

to use a specific key pair. If not set, a new key pair will be generated;

#:redirect-uri

to set the redirect URI that the application controls. It may just be a page showing the authorization code, with instructions on how to paste this code into the application. It should match one of the authorized redirect URIs in the client identifier endpoint.

If you want to set a state parameter for the redirection, you can do it by setting the guile parameter authorization-state.

Generic method: uri client-id (client <client>)
Generic method: key pair key-pair (client <client>)
Generic method: uri redirect-uri (client <client>)

Slot accessors for client.

Parameter: client

Define this parameter to set the client to use to access private data.

To access private data, you must identify yourself. The (webid-oidc client accounts) module lets you define accounts.

Class: <account> subject issuer id-token access-token refresh-token key-pair

Encapsulate an account. subject is your webid, while issuer is a host name. id-token is the decoded OIDC ID token, i.e. a pair of (header . payload), because we don’t need to show it to any other party, so its authenticity needs not be demonstrated. However, access-token is an encoded access token (into a string), because we don’t need to worry about its internals on client side.

There are different ways to initialize an account. First, you can save all parameters to some form of storage, and restore it by using the associated keyword arguments at construction time:

#:subject
#:issuer
#:id-token
#:access-token
#:refresh-token
#:key-pair

If you want to make a new account, you would ask the user for an identity provider, and pass it with #:issuer as the only initialized value. The constructor will log you in, using the authorization-process and anonymous-http-request function parameters.

If you want to refresh an access token, you would also set #:refresh-token.

In any case, when you don’t specify a value, it’s as if you passed #f.

Parameter: authorization-process

This function is called when an explicit user authorization is required, for instance because there is no refresh token and the access token expired. The function takes an URI as argument, with an additional #:reason keyword argument containing the reason for the authorization as a string. In this function, you should present the reason to the user and ask the user to browse this URI so that your application gets the authorization code.

Parameter: anonymous-http-request

This function is used as a back-end for private resource access, and to query the server configuration. It defaults to http-request from (web client).

Generic method: uri subject (account <account>)
Generic method: <account> set-subject (account <account>) (uri string or URI)
Generic method: uri issuer (account <account>)
Generic method: <account> set-issuer (account <account>) (uri string or URI)
Generic method: optional decoded ID token id-token (account <account>)
Generic method: <account> set-id-token (account <account>) (id-token optional ID token)
Generic method: optional encoded access token access-token (account <account>)
Generic method: <account> set-access-token (account <account>) (access-token optional access token)
Generic method: optional <string> refresh-token (account <account>)
Generic method: <account> set-refresh-token (account <account>) (refresh-token optional <string>)
Generic method: key pair key-pair (account <account>)
Generic method: <account> set-key-pair (account <account>) (key-pair optional key pair)

Slot accessors and functional setters for account.

If you intend to run a public network server as a client application, you may have multiple different users, but you should not let any user use any account. If this is the case, you can either store the accounts on the user agent storage (for instance, as a cookie), or store all of them on the server. If you choose to store the accounts on the user agent, at least use a new key pair for each of them. If you want to store the user database on the server side, be aware that no entity other than yourself will check that your user abides by any term of service, so it is possible that a single user makes a lot of accounts to annoy you and fill your hard drive with key pairs. If your application does not let random people to use it, you might want to use protected accounts, to help you check that the users cannot impersonate each other.

Class: <protected-account> (<account>) username encrypted-password

This superclass of <account> is protected by a username and password. It is constructed with the initializer keywords #:username and #:encrypted-password.

Generic method: <string> username (protected-account <protected-account>)
Generic method: <protected-account> set-username (protected-account <protected-account>) (username <string>)
Generic method: <string> encrypted-password (protected-account <protected-account>)
Generic method: <protected-account> set-encrypted-password (protected-account <protected-account>) (encrypted-password <string>)

Slot accessors and functional setters for protected-account.

Generic method: <account> invalidate-access-token (account <account>)

Indicate that the access token in account cannot be used. Before using account again, you will need to refresh the access token. This function does not mutate account.

Generic method: <account> invalidate-refresh-token (account <account>)

Indicate that the refresh token has been revoked for account. This is usually an indication that the user don’t want your application to access her private data. This function does not mutate account.

Generic method: <account> refresh (account <account>)

Refresh the access token.

Exception type: &authorization-code-required uri

If the login process requires the user to send an authorization code, an exception of this type will be raised, with an implicit invitation for the user to browse uri and follow the instructions.

The instructions will be handled by the redirect-uri in the login function. If your client is a traditional web application, the user will be redirected to this URI with an authorization code. If your client is a native application, then maybe that redirection URI should display the authorization code and invite the user to paste it in the appropriate place in the application.

When an exception of this type is raised during the login function, it is continuable, meaning that the login function will resume. You need to create an exception handler for an exception of this type, look up the uri, direct the user to browse it, get the authorization code back, and return the authorization code from the exception handler.

function: make-authorization-code-required uri
function: authorization-code-required? error
function: authorization-code-required-uri error

Constructor, predicate, and accessor for the &authorization-code-required exception type.

Exception type: &refresh-token-expired

The refresh token can be used to still perform requests on behalf of the user when perse is offline. However, if the refresh token expires while the user is offline, it is not possible to log in again, because it requires a new authorization code. So, it is not possible to recover from this error, and the refresh token is immediately discarded.

function: make-refresh-token-expired
function: refresh-token-expired? error

Constructor and predicate for the &refresh-token-expired exception type.

function: invalidate-access-token account

Discard the access token for account. It is not saved in the user database yet. This is roughly equivalent to log out.

function: invalidate-refresh-token account

Discard the refresh token for account. You still need to save the account.

Exception type: &token-request-failed response response-body

If the token endpoint is unable to deliver an identity token and an access token, this exception is raised with the identity provider response and response body. This exception cannot be continued.

function: make-token-request-failed response response-body
function: token-request-failed? error
function: token-request-response error
function: token-request-response-body error

Constructor, predicate, and accessors for the &token-request-failed exception type.

The (webid-oidc client) module provides the most useful function for a client.

function: request account uri . args

Perform a request on behalf of account, with the current value of the client parameter as the client, using as a backend the current value of anonymous-http-request.

Finally, to implement your application, there needs to be a public endpoint for the resource server to check that you are not impersonating another application. This endpoint can be served by any web server, but a convenience procedure is made available here:

function: serve-application id redirect-uri [#client-name] [#client-uri]

Return a handler for web requests to serve the application manifest and the redirection to transmit the authorization code. You should set the client-name to your application name and client-uri to point to where to a presentation of your application.


Next: , Previous: , Up: Top   [Contents][Index]