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:
- Unbox API reference
- Flow diagram for your use case (with step numbers corresponding to this page):
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 Unboxcode_challenge
: the encoded part of the PKCEcode_verifier
code_challenge_method
: onlyS256
is supportedresponse_type
: currentlycode
scope
: currently onlyopenid
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
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:
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).