Skip to content

Instantly share code, notes, and snippets.

@itskhanow
Last active January 20, 2022 20:27
Show Gist options
  • Save itskhanow/df5ce828015d4a6870aab9dcb4185f8b to your computer and use it in GitHub Desktop.
Save itskhanow/df5ce828015d4a6870aab9dcb4185f8b to your computer and use it in GitHub Desktop.

LoginID Integration WIP

This integration utilizes LoginID's client and backend SDKs to implement FIDO registration and authentication. This document assumes familiarity with the FIDO process. The integration to the ONEtech platform is specific to the app domain and all necessary configurations (clientIDs, private keys, etc.) are attached to the app's domain name and stored in the cluster. A ONEtech WorkflowAPI JWT that contains the correct domain is needed in all calls to the REST API as they will look up the necessary config using the domain property.

A number of different tokens may be referred to:

  • WORKFLOWAPI_TOKEN: This is the ONEtech WorkflowAPI JWT that we use on the platform.
  • SERVICE_TOKEN: This service token is generated using the private key stored in-cluster. This is needed to communicate with LoginID's REST API.
  • CREDENTIAL_TOKEN: This JWT is obtained by the client when they successfully authenticate and can be passed along with any workflow calls and can be verified that the caller is the authenticated user.

Flows

Registration

A new user account can be created using either "Register With FIDO" or "Register With Password". On successful completion the user's credential object can be obtained using the client store's bindable prop getFidoCredential() which will contain a CREDENTIAL_TOKEN which can be sent along with any workflow calls and used to verify the user using the /verify-credential-token REST API endpoint. This credential object can be stored locally on the client and checked first in the future to allow a user to remain logged in.

Authentication

An existing user can authenticate and log in using either "Authenticate With FIDO" or "Authenticate With Password". On successful completion the user's credential object can be obtained using the client store's bindable prop getFidoCredential() which will contain a CREDENTIAL_TOKEN which can be sent along with any workflow calls and used to verify the user using the /verify-credential-token REST API endpoint. This credential object can be stored locally on the client and checked first in the future to allow a user to remain logged in.

Authorize Device

An existing user can authorize a new device to access their account by either attempting to log in using their new device first or by pre-emptively requesting an authorization code.

In either scenario the workflow must call the /generate-auth-code REST API endpoint with the purpose property set as "add_credential" and the resulting auth code must be sent to the user either through an external communication channel (email or SMS) or directly in the app on a previously authorized device. Before that code can be used though, the end user must first use a previously authorized device to pass in their CREDENTIAL_TOKEN to the /authorize-code REST API endpoint with the purpose property set as "add_credential". The reason for this is to disallow anonymous parties to request authorization and intercept and use the code to gain access. The code must be approved by the authenticated user.

Finally, the authorized code can be used in "Add FIDO Credential" on the new device. A credential name can be specified to allow the user to manage which devices can continue to have access to their account.

Temporarily Authorize Device

This flow is similar to the last one but will not result in the new device being added to the user account's list of credentials. As in the previous flow, a call must be made to /generate-auth-code with the purpose property set as "temporary_authentication" and that code must be authorized by an authenticated user with /authorize-code passing in a CREDENTIAL_TOKEN and, again, with the purpose property set as "temporary_authentication".

On the new device that's being used to access the account temporarily, the "Request Temporary Authentication" Client Store action can be called using the username and code. This call will wait until the code has been authorized by an authenticated device for 2 minutes until the code times out. Once the code has been authorized the store action will return the user's credential object which can be retrieved with getFidoCredential(). In this case, it is not recommended to store the user credential object locally on the temporary device.

Account Recovery

This flow should be used sparingly and only in the case that a user has lost access to all previously authenticated devices as it bypasses the manual code authorization step from the authenticated user. A call can be made to /generate-recovery-code which will generate a pre-authorized code which needs to be sent to the user using external secure communication channels such as a verified email.

User Management

LoginID has several HTTP REST API calls that lets us manage user accounts. They can be found at LoginID API and require a SERVICE_TOKEN in the Authorization header which can be requested from the /generate-service-token endpoint. A service token needs to be generated with the specific scope required in the call and the scopes can be found here: LoginID Service Token Scopes

Store Actions

"Init LoginID"

initLoginId()

"Register With FIDO"

registerWithFido(username: string)

"Register With Password"

registerWithPassword(username: string, password: string, confirmPassword: string)

"Authenticate With FIDO"

authenticateWithFido(username: string)

"Authenticate With Password"

authenticateWithPassword(username: string, password: string)

"Add FIDO Credential"

addFidoCredential(username: string, code: number, credentialName: string)

"Request Temporary Authentication"

requestTemporaryAuthentication(username: string, code: number)

REST API Endpoints

Generate Service Token

Endpoint: https://loginid.onetechnology.com/generate-service-token

Header: Authorization: Bearer {{WORKFLOWAPI_TOKEN}}

Payload:

{
  "scope": "code.generate",
  "username": "itskhanow",
  "userid": "c80af3e6-2660-43a3-a1c1-7bf679299cba"
}

Response:

{{SERVICE_TOKEN}}

Verify Credential Token

Work In Progress

Endpoint: https://loginid.onetechnology.com/verify-credential-token

Header: Authorization: Bearer {{WORKFLOWAPI_TOKEN}}

Payload:

{
  "credentialToken": "{{CREDENTIAL_TOKEN}}",
  "username": "itskhanow"
}

Response:

{
  "iss": "loginid.io",
  "sub": "c80af3e6-2660-43a3-a1c1-7bf679299cba",
  "sid": "9b9cd28c-1df1-49f4-a2ac-379086475a5e",
  "nid": "c33ddede5085b9ea",
  "aud": "Uz1cZDo7jWdS4c7ta2hhHq4KDbLLCvrXxPpx20zd1ihlXfvcw4a1drkjwTUHU8FWnzGNYVOaQPj5mo5qTwIO2Q",
  "action": "login",
  "iat": 1641426887,
  "udata": "itskhanow"
}

Generate Authorization Code

Endpoint: https://loginid.onetechnology.com/generate-auth-code

Header: Authorization: Bearer {{WORKFLOWAPI_TOKEN}}

Payload:

{
  "username": "itskhanow",
  "codeType": "short || long || phrase (optional)",
  "purpose": "temporary_authentication || add_credential"
}

Response:

{
  "code": "527603",
  "expires_at": "2022-01-14T04:48:31Z",
  "is_authorized": false
}

Authorize Code

Endpoint: https://loginid.onetechnology.com/authorize-code

Header: Authorization: Bearer {{WORKFLOWAPI_TOKEN}}

Payload:

{
  "credentialToken": "{{CREDENTIAL_TOKEN}}",
  "username": "itskhanow",
  "code": 527603,
  "codeType": "short || long || phrase (optional)",
  "purpose": "temporary_authentication || add_credential"
}

Response:

{
  "expires_at": "2022-01-14T04:48:31Z",
  "is_authorized": true
}

Generate Recovery Code

Endpoint: https://loginid.onetechnology.com/generate-recovery-code

Header: Authorization: Bearer {{WORKFLOWAPI_TOKEN}}

Payload:

{
  "username": "itskhanow"
}

Response:

{
  "code": "679146",
  "expires_at": "2022-01-14T04:41:12Z",
  "is_authorized": true
}

Bindable Props

getFidoSupport() returns true/false

getFidoCredential() returns

{
  "is_authenticated": true,
  "client": {
    "id": "Uz1cZDo7jWdS4c7ta2hhHq4KDbLLCvrXxPpx20zd1ihlXfvcw4a1drkjwTUHU8FWnzGNYVOaQPj5mo5qTwIO2Q",
    "type": "directweb",
    "rp_id": "khanvideorecordertest.onetechnology.com"
  },
  "user": {
    "id": "c80af3e6-2660-43a3-a1c1-7bf679299cba",
    "username": "itskhanow",
    "namespace_id": "c33ddede5085b9ea",
    "type": "regular"
  },
  "credential": {
    "uuid": "61b57503-8b42-47d1-8b5f-a48bd2a15566",
    "name": "Linux (Chrome) - 61b57503",
    "type": "password"
  },
  "jwt": "{{CREDENTIAL_TOKEN}}"
}

Action Triggers

  • onLoginIdInit
  • onRegisterWithFido
  • onRegisterWithPassword
  • onAuthenticateWithFido
  • onAuthenticateWithPassword
  • onAddFidoCredential
  • onTemporaryAuthentication
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment