This is part two of a completely unknown number of linked articles as I’m writing them without even the slightest bit of aforethought. They’re not tutorials as such, but more documenting my progress and thinking as I forge onward building something.
It’s been a while since I’ve used IAP on iOS. This series of articles will follow my erratic thought process as I create the following:
- A small web app, managing anonymous user accounts and their credit balance
- An iOS application which allows you to top-up your account, restore purchases etc without the need to create an account.
This post will cover the authentication side of the app – I’m taking the new Laravel Sanctum functionality for a spin.
First thing I did was set up a new Laravel app, install Sanctum, and migrated all the things. I know I’m going to need an endpoint that accomplishes the following:
- Handle a POST request with some JSON data
- Check the request comes from a valid source
- Creates an anonymous user
- Issues a token for that user
- Returns a JSON response with the user token
My function ended up looking like this:
public function token(Request $request){ $validation = Validator::make($request->all(),[ 'key' => 'required', ]); if($validation->fails()) return response()->json(["errors"=>$validation->messages()], 200); //TODO: Something a bit more robust than this; probably use it to check against an Apps table or something like that if($request->key != "supersecretappidentifier") abort(403); //Create anon user. You could use your own user model. I've stuck with the Eloquent one and faked the data, as I figure I may allow users to create an account at a later stage. $faker = Factory::create(); try { $user = User::create([ 'name' => $faker->name, 'email' => $faker->email, 'password' => Hash::make($faker->password), ]); //Create the Sanctum token; again you'd probably use the name of the App or something $token = $user->createToken($request->key); return response()->json(["token"=>$token->plainTextToken], 200); } catch (\Exception $e) { return response()->json([ "error"=>true, "message" => $e->getMessage() ], 400); } }
Hit the endpoint with Postman and you’ll be given a shiny token to use in subsequent requests.
{"token":"C6UHgQXdrtCj7oEipaGCHU0Moq7uBGPpczEu1Lb1ApGpgMHSyfozQSwxvpRm524MdDbtrYBCNqU5s0Z5"}
Great! Now to make an app do it. Swift’s not my strong suit at the moment – I’m still writing most of my iOS code in Objective-C – so please bear with me.
We need functionality that does the following:
- Checks if there’s a token on the device
- If not, makes a POST request to our web service
- Retrieve and store the token in the iCloud Key-value storage
I’m using iCloud storage for this example, but it would be a lot better and safer to use an iCloud based Keychain in a production app.
We save in iCloud so that if the user uses the app on another device – say their iPad – they’ll be linked to the same account at the web service end, whilst remaining anonymous in the eyes of my application. You’ll need to add the iCloud Key-value storage capability to your app to make this work.
The code looks a little like this. I’m using AlamoFire to handle network requests.
let token = NSUbiquitousKeyValueStore.default.string(forKey: "laravelToken") if(token == nil) { let params: [String:String] = [ "key": "supersecretappidentifier" ] AF.request("http://credits.test/api/auth/token",method: .post, parameters: params, encoding:JSONEncoding.default).responseJSON { response in switch response.result { case .success(let JSON): let response = JSON as! NSDictionary let token = response.object(forKey: "token")! NSUbiquitousKeyValueStore.default.set(token, forKey: "laravelToken") NSUbiquitousKeyValueStore.default.synchronize() break case .failure: break } } } else { print(token!) }
The first time you run the app, it’ll make the request and store the token. Subsequent runs will print out the stored token.
That’s it for today I think – to recap, we’ve created a web service which creates an anonymous user and a token for the app to retrieve and store.
In the next article, I’ll add some credits functionality to the user and display our balance on the iOS device.