Tutorial: Login Using OAuth2 Client

Login Using OAuth2 Client

Rather than implement support for specific OAuth2 providers (with, for example, a GitHubProvider/GoogleProvider/&c.), Flitter Auth ships with a generic Oauth2Provider which supports the authorization_code OAuth2 method. The idea is that the configuration for the OAuth2 provider in Flitter is fine-grained enough that it should be adaptable to work with most OAuth2 providers.

Conceptual

OAuth2 authentication is a fundamentally different way of authenticating a user (as compared to the local database-driven auth, and the LDAP auth). Rather than providing a username and password to a login form on your application, the application redirects the user to the login page for a different provider.

Once the user has signed in with that provider, the provider's application redirects the user back to a specific endpoint on your application with a special token known as an authorization code. Flitter then takes this authorization code and (by making a web request from the server itself) redeems this authorization code for a bearer token, which can be used to access some API endpoint on the provider application.

Using that API bearer token, Flitter makes another request (again from the server) to a configured API endpoint on the provider application (authenticating with the bearer token) to retrieve information about the user. That information is then loaded into the module:flitter-auth/model/User~BaseUser model.

Configuration

Flitter Auth ships with an example config for an OAuth2 provider. This config provides an example allowing users to "Sign-In With GitHub." This means that the users authenticate with GitHub, GitHub issues Flitter an auth token, then Flitter uses that token to request the user data from api.github.com, populating the User model.

Here's the example:


example_oauth: {
    type: 'Oauth2Provider',
    enable: env('AUTH_OAUTH2_ENABLE', false),

    source_name: env('AUTH_OAUTH2_SOURCE_NAME', 'GitHub'),
    source_client_id: env('AUTH_OAUTH2_CLIENT_ID'),
    source_client_secret: env('AUTH_OAUTH2_CLIENT_SECRET'),

    // Login page destination where the user will be redirected to on login
    // %c will be interpolated with the client id
    // %r will be interpolated with the redirect callback url
    //  NOTE: This url is the same as the login page - /auth/oauth2/login
    source_login_page: env('AUTH_OAUTH2_LOGIN_REDIRECT', 'https://github.com/login/oauth/authorize?client_id=%c'),

    // Information about the OAuth2 Callback
    callback: {
        // URL query parameter name with the authorization_code token
        // e.g. ?code=XXXXXXXXXX
        token_key: 'code',
    },

    // Information about the endpoint flitter-auth will use to redeem
    // the authorization_code token for a bearer token
    source_token: {
        endpoint: 'https://github.com/login/oauth/access_token',

        // Field name where the authorization_code token will be specified in the request
        token_key: 'code',

        // Field name for the client id
        client_id_key: 'client_id',

        // Field name for the client secret
        client_secret_key: 'client_secret',

        // Field name for the grant_type ('authorization_type')
        grant_type_key: 'grant_type',

        // Field name where the bearer token will be specified in the response
        response_token_key: 'access_token',
    },

    // Information about the endpoint flitter-auth will use to get
    // user information after it retrieves a bearer token
    user_data: {
        endpoint: 'https://api.github.com/user',
        method: 'get', // 'get' or 'post' only

        // In the response data, what key is the user data in?
        // e.g. if 'data', then {'data': { ... }}
        // Set falsy to assume the data exists in the root: { ... }
        // data_root: 'data',

        // Value that prefixes the token in the 'Authorization: ' header.
        // e.g. 'token ' would mean 'token a0fw93ja0w93ja093wj'
        //      'Bearer ' would be 'Bearer 0329j0239dj209j3209jd'
        token_prefix: 'token ',

        // Mapping of user model attributes to OAuth2 return data from the endpoint
        // Note that uuid is not allowed, and uid is required
        attributes: {
            uid: 'login',
        },
    },
},

This creates an auth provider called example_oauth that loads most of its parameters from the environment. Let's look at each of these parameters in turn:

OAuth2 Parameters

type (default: Oauth2Provider)

This is the name of the provider class to use. For OAuth, it will always be Oauth2Provider.

enable (default: false)

If true, users will be allowed to authenticate with this provider.

source_name

The human-readable display name for the authentication provider. In this case, that readable name is "GitHub".

source_client_id

This is the unique identifier for your application. This is issued by the target provider. For example, you would generate a client secret in your GitHub settings.

source_client_secret

This is the unique secret for your application. This is passed along when the server requests the user's bearer to prove that the server is legit. This should be kept... well, secret.

source_login_page

This is the URL where users will be redirected to sign in with the provider application. All references to %c in this string will be replaced with the client_id. All references to %r will be replaced with the URL the provider application should call back to once the authentication has completed.

callback

An object containing information about the callback that occurs when a user has successfully authenticated with the provider application.

callback.token_key

This is the key name of the field on the request where the authorization code will be stored when the client request is redirected.

source_token

An object containing information telling Flitter how to exchange the authorization code for a bearer token.

source_token.endpoint

URL of the API endpoint to call to redeem the auth code.

source_token.token_key

Name of the field in the request where the auth code should be specified.

source_token.client_id_key

Name of the field in the request where the client ID should be specified.

source_token.client_secret_key

Name of the field in the request where the client secret should be specified.

source_token.grant_type_key

Name of the field in the request where the grant type should be specified. This is always authorization_code.

source_token.response_token_key

Name of the field in the response where the bearer token will be specified.

user_data

After retrieving the bearer token, Flitter Auth must make a request to some endpoint to get user information. This is an object containing information for making that request and parsing the response.

user_data.endpoint

URL of the API endpoint to call to fetch the user data.

user_data.method

What request method? get or post only!

user_data.token_prefix

Specifies the prefix before the token in the Authorization header. E.g. token 2309j2093dj2093j or Bearer aw09ejf0w9ej0f9sdjfiosdkjf or blank to disable prefix.

user_data.data_root

If the user data is returned nested in a property of the request, specify that property here (e.g. data). If the user data is returned in the root of the request, don't set this value.

user_data.attributes

An object mapping fields on the module:flitter-auth/model/User~BaseUser model to the fields on the response.

user_data.attributes.uid

This mapping is REQUIRED and must be provided by the configuration.

OAuth2 Callback URL

Provider applications redirect the user back to a specific URL once authentication with that provider is successful. For Flitter Auth, this is the URL of the login page:

https://your.app.url/auth/PROVIDER NAME/login