I was exploring the possibility of getting the auth token in bash using certificate authentication. Here are two examples how to obtain access token, one for Microsoft Graph and the other one for Google APIs.
Both scripts are similar:
- create jwt payload/claims
- sign header +payload with private key of the certificate uploaded to Microsoft/Google
- post data to token endpoint
- acquire access_token
A bit of explanation
base64 -w 0 | tr '/+' '_-' | tr -d '='
- this is simple base64url encodingbase64 -w 0
means that data won't be broken in multiple lines,tr '/+' '_-'
is used to replace/
with_
and+
with-
, and finallytr -d '='
is used to remove=
which is standard base64 paddingopenssl dgst -sha256 -sign $key_file
is signing input with certificate key stored in the$key_file
date +%s
is current timestamp, and$(($ts + 600))
adds 10 minutes of token validity
Microsoft uses certificate fingerprint (thumbprint) in jwt header and it is a binary value encoded as base64url.
openssl x509 -fingerprint -noout -in $cert_file
will produce something likeSHA1 Fingerprint=AA:BB:CC:DD:EE...
after whichcut -d '=' -f 2
is used to get everything right of the=
sign (the fingerprint), which is then converted into binary usingxxd -r -p
and finally converted into base64url
It also uses "a Guid" for unique identifier of a jwt wherecat /proc/sys/kernel/random/uuid
is used to create it.
In the end,jq
is used to extractauth_token
into the file or to display the error message in case authentication was not successful.
It is probably easier just to use vendor provided tools or libraries, but sometimes having a simple shell script is just good enough.
Microsoft Graph
#!/bin/bashset-eclient_id='<replace_with_client_id>'tenant_id='<replace_with_tenant_id>'cert_file='my.crt'#certificate (used for fingerprint)key_file='my.key'#certificate private key (for signing)cert_hash=$(openssl x509-fingerprint-noout-in$cert_file |cut-d'='-f 2 | xxd-r-p |base64-w 0|tr'/+''_-' |tr-d'=')jwt_header="{\"alg\":\"RS256\",\"typ\":\"JWT\",\"x5t\":\"$cert_hash\"}"ts=$(date +%s)part_aud="\"aud\":\"https://login.microsoftonline.com/$tenant_id/oauth2/v2.0/token\""part_nbf="\"nbf\":$ts"part_exp="\"exp\":$(($ts+600))"part_jti="\"jti\":\"$(cat /proc/sys/kernel/random/uuid)\""part_iss="\"iss\":\"$client_id\""part_sub="\"sub\":\"$client_id\""jwt_payload="{$part_aud,$part_exp,$part_iss,$part_jti,$part_nbf,$part_sub}"token_data="$(echo-n$jwt_header |base64-w 0 |tr'/+''_-' |tr-d'=').$(echo-n$jwt_payload |base64-w 0 |tr'/+''_-' |tr-d'=')"signature=$(echo-n$token_data | openssl dgst-sha256-sign$key_file |base64-w 0 |tr'/+''_-' |tr-d'=')assertion="$token_data.$signature"resp=$(curl-Ssl-X POST"https://login.microsoftonline.com/$tenant_id/oauth2/v2.0/token"\--data-urlencode"client_id=$client_id"\--data-urlencode'scope=https://graph.microsoft.com/.default'\--data-urlencode'client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer'\--data-urlencode"client_assertion=$assertion"\--data-urlencode'grant_type=client_credentials'\)ifecho$resp |grep-q'access_token';thenecho$resp | jq-j'.access_token'>access_tokenelseecho$resp | jq-r'.error + " error:\n" + .error_description'exit1fi
Source:
Google APIs
#!/bin/bashset-eclient_email='client@your-project-name.iam.gserviceaccount.com'subject_email='subject@example.com'#user that will be impersonatedscopes='https://www.googleapis.com/auth/<scope1> https://www.googleapis.com/auth/<scope2>'key_file='my.key'#certificate private key (for signing)jwt_header="{\"alg\":\"RS256\",\"typ\":\"JWT\"}"ts=$(date +%s)part_iss="\"iss\":\"$client_email\""part_sub="\"sub\":\"$subject_email\""part_scope="\"scope\":\"$scopes\""part_aud="\"aud\":\"https://oauth2.googleapis.com/token\""part_exp="\"exp\":\"$(($ts+600))\""part_iat="\"iat\":\"$ts\""jwt_payload="{$part_iss,$part_sub,$part_scope,$part_aud,$part_exp,$part_iat}"token_data="$(echo-n$jwt_header |base64-w 0 |tr'/+''_-' |tr-d'=').$(echo-n$jwt_payload |base64-w 0 |tr'/+''_-' |tr-d'=')"signature=$(echo-n$token_data | openssl dgst-sha256-sign$key_file |base64-w 0 |tr'/+''_-' |tr-d'=')assertion="$token_data.$signature"resp=$(curl-Ssl-X POST'https://oauth2.googleapis.com/token'\--data-urlencode'grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer'\--data-urlencode"assertion=$assertion"\)ifecho$resp |grep-q'access_token';thenecho$resp | jq-j'.access_token'>access_tokenelseecho$resp | jq-r'.error + " error:\n" + .error_description'exit1fi
Source:
https://developers.google.com/identity/protocols/oauth2/service-account#httprest
Code
Top comments(0)
For further actions, you may consider blocking this person and/orreporting abuse