Old documentation - General¶
Here is the documentation portal of the MyUnbox Authorization server
Reminder:
- client: application linked to
MyUnbox
which is allowed to trigger user authentication and receive aJWT
. - user: an end user, using the
client application
andMyUnbox
.
You may find also the swagger
documentation through the following path: <auth server cname>/swagger-ui/
with more precise schema definitions.
Requirements¶
To use any flow, you will need at the least a client_id and maybe a client_secret if your application is private: please contact us and we will provide it.
Here are some information you will need to provide, we will defined together some others:
- url website
- url logo
- url callback
- app description (allowing us to determine if it is a public or private app, requiring or not secret)
- wished scopes (openid, profile, email, mobile)
- token validity duration (anyway this have to be short)
- refresh token enable or not (depends on the type of application again)
OAuth 2.0 flows¶
Our implemented flows are following the OAuth 2.0
RFC from an client perspective and should be compatible with any standard OAuth 2.0 client lib (for the webflow only). If you encounter any issue contact us.
At this time, we are only offering the code
flow through the use of PKCE
through the use of a remote mobile app called MyUnbox
.
In theory could skip the use of MyUnbox and do everything on your own but that would mean dealing on your side generation/backup/signing (which is opensource from Cardano
specifications).
Configuration¶
Automatic¶
If your client libray supports it you could use directly this url: <auth server cname>/.well-known/openid-configuration
.
This endpoint is describing all available OAuth 2.0 endpoints following the accordingly RFC.
JWKS¶
In order to verify on your side the token, you can retrieve our keys through this call (unless you are using the automatic configuration): /.well-known/jwks.json
Warning, do not store permanently they keys from these endpoints, we might from time to time rotate our keys according to our convenience without notifying anyone (security reason).
Classic Web Application Workflow¶
Here is the happy path, without SSO involved:
- client_id triggers an
/authorize
request, redirecting the end user to our authorization server. - The authorization server then redirect the user to a login page.
- The login page will display some client information and a QRCode.
- User will grab his mobile app
MyUnbox
for scanning the QRCode, the app will present some information about the login and let himconsent
. - The login page will notified by the authorization server to redirect the user to client application (using provide callback url).
- The client will capture, through the callback, the response
code
and will call the authorization server through/token
endpoint call for exchanging it for a valid JWT.
Peculiar case for SSO:
- If the required scopes are already consent and the user is already authenticated, the whole signature mechanism involving MyUnbox is dropped, the client will get back immediately after the
/authorize
thecode
. - If at least one scope is not consented, the flow is identical to the without SSO involved.
Headless MyUnbox/Api flow¶
[STILL UNSUPPORTED?/INELIGIBLE FOR MVP?]¶
Warning¶
This flow is at the moment not fully supported.
We have all api that would allow any app to login, currently used by MyUnbox
itself but, we do not have implemented any communication mechanism between mobile application yet.
Leads: using deeplink etc.
Details¶
This Flow is slightly different as there is no http
redirect_uri
. Everything is done through discussion
between your mobile app and MyUnbox
.
To use the api flow you must position a specific header --header 'Accept: application/json'
in all your requests.
As a developer, you will discuss with the MyUnbox Authorization server
until you reach the login phase (retrieving what needs to be signed) and then discuss
with the mobile app MyUnbox
to sign a content (what is behind the QRCode
in webflow) and then submit it.
Overall high level Workflow (some parameters are not spoken of for better understanding, have a closed look at the endpoints definitions):
/authorize
will get you alogin_code_to_sign
(PKCE still required)- Ask
MyUnbox
native app to sign this code. The expected result from MyUnbox would be a signature plus the pub_key used - Post the result to the
/login
endpoint which would result in acode
for next call - Post the code to
/token
endpoint which will get you the finalJWT
SSO [PART OF LOGIN MVP?]¶
As we are supporting SSO, if your application has already approved all its scopes and if the user if already authenticated in through our server you can get back immediately the code
for the token
exchange endpoint.
Remember that you will still have to redirect your user with the authorize
endpoint as usual to get a new token.
Logout [NOT NOW]¶
You can perform a logout through the following redirection, so the user will land on a logout
page we designed here, not your website.
Warning so! This endpoint is not at all what should be use directly in production, it will not destroy all opened session or revoke any delivered jwt.
It will only kill the SSO session and obviously only concern the webflow.
In a distant future, the logout endpoint will trigger an event from which all applications (at least the branded Unbox ones) could listen from, allowing them to perform a logout.
GET /openid/logout
Query urlencoded parameters¶
Parameter | Required | Schema | Description |
---|---|---|---|
post_logout_redirect_uri | No | String | Should be the url where you want to redirect the user after logout |
Response¶
If post_logout_redirect_uri
is postioned, user will be redirect to, if not user will fall into the our logout page in final state.
PKCE requirements¶
https://www.rfc-editor.org/rfc/rfc7636.html#section-6.2
PKCE is a mandatory mechanism to protect the token exchange. You will need to initiate a /authorize
with its hash value to later use the clear value during the token exchange:
- Generate random value with enough entropy, at least 12 characters: this is the
code_verifier
- Generate the
SHA-256
and encode it in base64 without the leading: this is thecode_challenged
- Formula
BASE64URL-ENCODE(SHA256(ASCII(code_verifier)))
- Most important part is to encode in base64 without padding!
// In Rust
let mut sha256 = Sha256::new();
sha256.update(code_verifier.as_bytes());
let code_challenge = base64::encode_config(sha256.finish(), base64::URL_SAFE_NO_PAD)
// In Javascript
// Sure this could be better coded
async function generateCodeChallenge(codeVerifier) {
var digest = await crypto.subtle.digest("SHA-256",
new TextEncoder().encode(codeVerifier));
return btoa(String.fromCharCode(...new Uint8Array(digest)))
.replace(/=/g, '').replace(/\+/g, '-').replace(/\//g, '_')
}
Library¶
You can also use native library like this one in react native Example that would genrate for your the two values:
{
"codeChallenge":"FrKXvAasmPJAnMh9jPOW-HMQouSjPYAwlMU-RP20vLs",
"codeVerifier":"xDshz4RJuwAMLOa8j41R1gR-NhLMv7WoU2LiC-bqrwNpnU70l1mlZocMSh3pABbsWiIHBPKFbPEuFbZy_cQiRWMQjBXoxPY9FUe9STC5h4vJ7wyGKMDKKo9sQtraBScm"
}
Authorize¶
This api is the entry point of any application that wish to retrieve an end-user JWT
.
In order to use this endpoint you will have to use the PKCE mechanism.
The redirect_uri, cannot in reality be optional if you use on your own the endpoint. The only way it could be optional is when it is used by the MyUnbox
mobile application.
GET /oauth2/authorize
Successful http code: 200
QUERY params¶
Parameter | Required | Schema | Description |
---|---|---|---|
response_code | Yes | ResponseCodeEnum | Available values : code |
client_id | Yes | String | Client identifier delivered by UNBOX |
scope | Yes | String | List of scopes separated by space ex: openid or openid admin |
code_challenge | Yes | String | Client generated code_challenge ref PKCE |
code_challenge_method | Yes | String | Available values: S256 |
state | No | String | Client state for callback, to reposition the end-user where he should be |
redirect_uri | No | String | Where to redirect the user when the flow ends with or without success |
QUERY Header to differentiate between Webflow and API¶
By default flow is considered to be used from web, with a QR code in parallel to continue signing.
If your intent is to call the flow as an API, you need to add header indicating accept JSON content type as following ing curl --header 'Accept: application/json'
.
Webflow response¶
Server will redirect the user to the login page, displaying a QRCode to be scanned and signed by MyUnbox
application. If everything goes well, user will be redirect to the redirect_uri
with a code to use through the token
exchange endpoint.
API response¶
This response, when the mentionned earlier header is applied, will reply to you with a plain json providing information on the login request.
JSON output response¶
Property | Required | Schema | Description |
---|---|---|---|
login_code_to_sign | True | String | Code to sign, base64 encoded version. |
Decoding login_code_to_sign¶
You can decode64
login_code_to_sign
which should give you a JSON
describing the actual login request, which is used to display info to the user.
Property | Required | Schema | Description |
---|---|---|---|
random_code | True | String | Random value for entropy |
expiration_in_secs | True | Number | indicates in how many seconds this code will expire |
client_id | True | String | Third party application identifier that is trying to access to the MyUnbox account/profile/identity |
client_logo | False | String | Optional uri to the client logo, must be https link |
redirect_uri | False | String | Where to redirect the user, this is used by the server to redirect the user to the third party application (callback uri) |
client_website | False | String | Uri of the third party |
scope_to_approve | True | Tokenized Scope (space) | List of scopes asked by the third party |
time | True | DateTime | When this information have been generated |
Login as Sign/Consent¶
Next step is to sign the code_to_sign
from previous call /authorize
.
Signature can be done using your Cardano
private key.
Parameters / Request¶
Property | Required | Schema | Description |
---|---|---|---|
pub_key | True | String | ED25519 format pubkey (bech32) related to the private key you used for signing |
code_to_sign | True | String | The login request to sign |
signature | True | String | signature of code_to_sign, as hex string |
storage_token | False | String | Do not care at the moment of this field you can pass it to null |
curl --location --request POST 'https://clx-webx-authorization-server.dev.unboxuniverse.io/oauth2/authorize/login' \
--header 'Cookie: id=UZIEd0tLRAky%2FCjnOGkGgOSJ+x2gJNFOyjmmDbaw5EDHAaZhSIko%2FYyJVc7kDmXm78J0Q%2FWWcZirUamjvRFz8rFSEoc5bS8Z%2F3Q5gqCwiI29wGLOikcxWPUnOk0%3D;' \
--header 'Content-Type: application/json' \
--data-raw '{
"pub_key": "ed25519_pk13getm9cptcz49kvmmas3tt8vqv364drg6klglwawy3tcjsg49vpsxxanxu",
"code_to_sign": "eyJyYW5kb21fY29kZSI6Ik1OMW55b3ZyTjAiLCJleHBpcmF0aW9uX2luX3NlY3MiOjE4MCwiY2xpZW50X2lkIjoiN2I3MGJlNTMtNzhhOC00M2JjLWFjYzMtZTQ4NDZkMjJkZWRmIiwiY2xpZW50X25hbWUiOiJQb2MgQ29kZSBIYW5kbGVyIiwiY2xpZW50X2xvZ28iOm51bGwsInJlZGlyZWN0X3VyaSI6bnVsbCwiY2xpZW50X3dlYnNpdGUiOm51bGwsInNjb3BlX3RvX2FwcHJvdmUiOm51bGwsInRpbWUiOiIyMDIyLTEwLTE4VDE1OjU1OjIzLjUxNTM0NjAzMloifQ==",
"signature": "337b2bb7c183ceaac4dab8562e58ab7bf2a3525557728059ddbd6b68a4a4babded1ec82c0a4776b828698eef393074fc99a866c596a5193c242697628739d008",
"storage_token": null
}'
Output¶
There is two different outputs.
JSON output API Flow¶
Http status: 200
.
Output Webflow¶
Nothing! A simple 204
http status, the page showing the QRCode will do the rest of the job.
Token request¶
Last step, once you get your hand on the code
, you can exchange it against JWT
token.
POST /oauth2/token
curl --location --request POST '/oauth2/token' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'grant_type=authorization_code' \
--data-urlencode 'code=CODE' \
--data-urlencode 'redirect_uri=REDIRECT_URI' \
--data-urlencode 'client_id=CLIENT_ID' \
--data-urlencode 'client_secret=CLIENT_SECRET' \
--data-urlencode 'code_verifier=CODE_VERIFIER'
Form urlencoded parameters¶
Parameter | Required | Schema | Description |
---|---|---|---|
grant_type | Yes | String | Value must be authorization_code |
code | Yes | String | Value you got from either a direct call to /login or the redirection to your app from the login page |
redirect_uri | No | String | Required if your client has a redirect_uri (webflow) |
client_id | Yes | String | Client identifier |
client_secret | No | String | Optional client secret (private app can have a secret, public no) |
code_verifier | Yes | String | Clear code used with PKCE during /authorize |
JSON output response¶
Property | Required | Schema | Description |
---|---|---|---|
access_token | Yes | String | Json Web Token |
scope | Yes | String | List of scopes separated by space |
refresh_token | No | String | Refresh token to be used to get back a new JWT. Refresh token can only be use once. |
expires_in | Yes | Number | Number of seconds before JWT expires |
token_type | Yes | String | Token type, should be "Bearer" |
Refresh token: get a new JWT!¶
The endpoint is the same as the token exchange but with different parameters (and output)
POST /oauth2/token
curl --location --request POST '/oauth2/token' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'grant_type=refresh_token' \
--data-urlencode 'client_id=CLIENT_ID' \
--data-urlencode 'client_secret=CLIENT_SECRET' \
--data-urlencode 'refresh_token=REFRESH_TOKEN'
Form urlencoded parameters¶
Parameter | Required | Schema | Description |
---|---|---|---|
grant_type | Yes | String | Value must be refresh_token |
client_id | Yes | String | Client identifier |
client_secret | Maybe | String | Required if your client has a scecret (private app) |
refresh_token | Yes | String | Previously delivered refresh token (must not be expired) |
JSON output response¶
See above, same as the Exchange for token
.
Bonus: Storage token¶
This is a the unique secret couple pub_key/client_id
is related to the profile data storage.
If the user is involved during the /authorize
process, meaning he signed with his private key, the client will get back in the JWT
the storage_token as an extra claim.
But if the JWT
is coming from an SSO
(scope requested already approved) then the storage token will not be present.
WARNING
: it is up to the client to keep on its side the storage token as a secret with the according security.
If for any reason, the client_id lost the secret, he might be able to get it back by triggering a new /authorize
request with the scope storage-token
. As this scope will never be approved
the user signature will always be part of the flow (even if SSO is on).