Skip to content

The login process with cURL

This page walks you through the login process. It uses cURL examples you can use with your own parameters and arguments.

As you make your way down this walkthrough, you might also want to refer to the following reference materials:

1. Press Login button and send code challenge

The login sequence is initiated when the end user clicks the login CTA (button or otherwise) on the client mobile app or desktop site.

In order to get the Login QR code back from /authorize, you must integrate OAuth 2.0 credentials in your application. This boils down to implementing a Login button such that pressing it sends to /authorize the same parameters as the cURL request below. 

2. Send code challenge

The client sends the following mandatory parameters to the Unbox auth server's /authorize endpoint, including the credentials of Client ID and PKCE code challenge (required as part of the standard OAuth 2.0 flow):

  • client_id: client ID provided by Unbox
  • code_challenge: the encoded part of the PKCE code_verifier
  • code_challenge_method: only S256 is supported
  • response_type: currently code
  • scope: currently only openid

You can issue the call in cURL as follows:

curl 
    --location 'https://clx-webx-authorization-server.unboxuniverse.io:443
    /oauth2/authorize
    ?client_id=<YOUR-CLIENT-ID>
    &code_challenge_method=S256
    &code_challenge=<YOUR-CODE-CHALLENGE>
    &response_type=code
    &scope=openid' \
    --header 'Accept: application/json'

However, because the call comes from a browser, the /authorize endpoint recognizes this and knows how to redirect to the auth page and display the login QR code on that page.

3. Receive login code to sign

If successful, the /authorize endpoint responds with a login_code_to_sign back to the client. If the Login button was implemented correctly, this results in the user being redirected to an auth page that displays a Login QR code (with the login_code_to_sign embedded in it).

{
  "login_code_to_sign": "ewoicmFu...NDZaIgp9"
}
The login_code_to_sign is the following JSON object encoded as a base64 string:

{
  "random_code": "d8A...ira",
  "expiration_in_secs": 180,
  "client_id": "7189...2d8703",
  "client_name": "MyUnbox",

  "client_id": "a28bb2...ab27c5",
  "client_name": "The Name of the Client",
  "client_logo": "https://www.theclientapp.app/logo.png",
  "redirect_uri": "https://unbox-clientapp:9000/logged-in",
  "client_website": "https://www.theclientapp.app/",
  "scope_to_approve": "openid",
  "server_uri": "https://0-clx-webx-authorization-server.uat.unboxuniverse.io",
  "time": "2024-05-01T19:32:17.190538246Z"
}

However, the signing to be done gets performed later on the encoded string, not on the JSON embedded inside it (presented above just for completeness' sake.)

As such there is no action to be performed on the content you see above.

Instead, take the long base64-encoded string of the login_code_to_sign as it arrived, and use XYZ to sign it with a private key as follows.

4. Pass the login code to sign to XYZ

The client takes the received login_code_to_sign and passes it as is to the XYZ mobile app, where it will be signed after the end user consents to the scope requested by the client.

This is done via different methods depending on the type of client app.

Mobile client app

The client sends the login_code_to_sign to XYZ directly (or takes the end user to their mobile app store to download XYZ first).

Client desktop app

The client sends the login_code_to_sign to XYZ indirectly, by getting the end user to scan a QR code with their mobile device.

Before sending the login_code_to_sign to the client, the /authorize endpoint first embeds the login_code_to_sign in a QR code, and then displays that webpage to the user client-side. The client doesn't have to do anything.

The user scans the QR code with their mobile device. Scanning the QR code either launches XYZ directly, or sends the user to their mobile app store to download XYZ first.

5./6. XYZ signs login code to sign

XYZ asks for the end user's consent. After the end user issues consent to the requested scope of access, XYZ uses its private key to do perform the following two actions: * sign the login_code_to_sign * generate a public key

Signing the login_code_to_sign with the private key generates the signature. Sending the signature and the public key together categorically guarantees to the recipient that the message was sent by the owner of the private key from which the public key was derived (and that the message was not modified in transit).

7./8. XYZ sends the signature

XYZ assembles the triplet of login_code_to_sign, signature, and the public key into a JSON package that looks as follows:

{
    "pub_key": "AAAAB3Nz~ma...Oqojqh$",
    "code_to_sign": "ewoicmF...MzgyNDZaIgp9",
    "signature": "eyJyYW5km...yI6IkhTMjU2In0.e30.xd_T4Wn2S...XPKmJGqc"
}

XYZ then sends this triplet to the auth server via one of two routes:

  • Mobile client app: XYZ first sends the triplet to the mobile client app, which then sends it to /authorize/login.

  • Client desktop site: XYZ sends the triplet to /authorize/login directly.

The triplet is sent not via query parameters, but as JSON in the body of a POST request which looks as follows:

curl --request 'POST' \ 'https://docs-internal.dev.unboxuniverse.io/oauth2./authorize/login' \
--header "Content-Type: application/json" \
--data '
{
    "pub_key": "AAAAB3...jqh$",
    "code_to_sign": "ewoicmF...Igp9",
    "signature": "eyJyYW...jU2In0.e30.xd_T4...PKmJGqc"
}
'

8. The login sequence continues...

The auth server's /authorize/login endpoint recognizes the original login_code_to_sign and can use the public key to decrypt the signature back into this exact login_code_to_sign.

If successful, this guarantees to the auth server that the original sender of the triplet is the same entity that holds the private key that generated this public key.

As a result, the auth server can now advise the client that it is safe to display to the end user the logged-in part of their interface (desktop website or mobile).

Additionally, the auth server sends to the client a code which the client can send to the auth server's /token endpoint and exchange it for an access token.

The code looks like this:

{
  "code": "umZG7tX2N...jMtNWE1Yzc"
}

9. Client asks for access token

The client sends the code received from /login endpoint (plus the PKCE code_verifier) to the /token endpoint.

The POST request looks as follows:

curl --request 'POST' \ 
'https://docs-internal.dev.unboxuniverse.io/oauth2./authorize/token' \
--header "Content-Type: application/json" \
--data '
{
    "code": "umZG7tX2N...jMtNWE1Yzc",
    "code_verifier": "ewoicmF...Igp9",
    "grant_type": "~authorization_code",
    "client_id": "a28bb2...ab27c5"
}'

10. Client receives the access token

The /token endpoint issues an access token to the client.

Server replies with a 3000-second bearer access token with openid scope and a refresh token:

{
    "access_token": "ey2435...c7zq",
    "scope": "openid",
    "refresh_token": "ey2435...c7zq",
    "expire_in": "3000",
    "token_type": "Bearer"
}

As a side note, the access token looks like this inside:

{
    "sub": "ed255...f4ku",
    "iss": "https://server.unboxuniverse.io/",
    "aud": "abcd28...27c5",
    "scope": "openid",
    "pub_key_hash": "08dcdc...8ee5",
    "iat": "1712913667",
    "exp": "1712913667"
}

Note: If you try to sign in more than once, you just get taken to the success part. However, if you change scope, the end user will have to be taken through the entire login procedure in order to be able to provide scope consent. Additionally, when you configure a client, you can have some scopes that are auto-approved (or understood/implicit).